關(guān)于 DDD 對前端的指導(dǎo)工作

DDD - Domain-driven design荔仁,領(lǐng)域驅(qū)動設(shè)計伍宦。很多人喜歡把事情分的很清,這是后端的設(shè)計思想乏梁,對我們前端有什么影響呢次洼?其實不然,javascript是一種面向?qū)ο蟮拈_發(fā)語言遇骑,既然是面向?qū)ο舐艋伲覀兙涂梢赃m用任何的設(shè)計思想。

當(dāng)我們在討論DDD的時候质蕉,我們在討論什么势篡?

什么是Domain?如何driven design模暗?這些太過拘于概念禁悠,我們以一些實際的例子,來看看兑宇,DDD是一種什么思想碍侦。

以個人為例,我們擁有年齡隶糕、身高瓷产、體重這樣的屬性,先排出其他影響因素枚驻,我們假設(shè)身高和體重只受到年齡影響濒旦,由此我們可以進(jìn)行如下設(shè)計,在class Person中再登,包含三個Property分別是age年齡尔邓、weight體重,height身高锉矢。

通常來說梯嗽,在年齡的增長過程中,體重沽损、身高會有不同階段的變化灯节,我們假設(shè)變化的公式為weight = f(age)height = f(age)則有下面序列圖

序列圖

也就是weightheight的變化是受age影響的,那么如果我們統(tǒng)一封裝在Person類中镶奉,這個類的領(lǐng)域就會變得很奇怪入篮,所謂基本的屬性绿饵,為什么類本身會需要對基本的屬性有方法去處理變化呢惠窄?

DDD設(shè)計

領(lǐng)域驅(qū)動設(shè)計在這里引入了 值對象 的概念凑兰,根據(jù) 單一職責(zé)迪米特法則雳窟,把weightheight這樣的具有變化特點(diǎn)的值负间,轉(zhuǎn)為對象的形式苛秕,也就是面試對象三大特點(diǎn)之一的 封裝唯笙,所謂 封裝變化螟蒸。

// Weight.js
class Weight {
  #weight = "opps";

  constructor(age) {
    this.#weight = this._handleAgeStateWeight(age);
  }

  getWeight() {
    return this.#weight;
  }

  _handleAgeStateWeight(age) {
    if (age < 24) return "normal weight";
    else return "fat weight";
  }
}

// Height.js
class Height {
  #height = "opps";

  constructor(age) {
    this.#height = this._handleAgeStateHeight(age);
  }

  getHeight() {
    return this.#height;
  }

  _handleAgeStateHeight(age) {
    if (age < 24) return "normal height";
    else return "no growing";
  }
}

// Person.js
class Person {
  #age = 24;
  #weight = "opps";
  #height = "opps";

  constructor(age = 24) {
    this.#age = age;
    this.#weight = new Weight(this.#age).getWeight();
    this.#height = new Height(this.#age).getHeight();
  }

  getPersonInfo() {
    console.log("age", this.#age);
    console.log("weight", this.#weight);
    console.log("height", this.#height);
  }
}

看到這里,你們是否對DDD領(lǐng)域驅(qū)動設(shè)計有一定了解了呢崩掘?

個人拙見:值對象的概念是 單一職責(zé)迪米特法則 的合集七嫌,更注重顆粒度,無疑苞慢,這種做法實現(xiàn)了面向?qū)ο蟮母邇?nèi)聚低耦合诵原,但是同樣的,在內(nèi)存開銷和項目初期增加了巨大的問題挽放。

領(lǐng)域驅(qū)動設(shè)計是一種大型項目構(gòu)建比較推薦的設(shè)計绍赛,通過這樣的設(shè)計,我們可以對項目形成較好對管理成本辑畦,接手項目的時候吗蚌,可以對最小顆粒進(jìn)行版本迭代和更新從而產(chǎn)生最小的影響。

這不是必須要求你的項目就一定要這樣做

因為初期成本太高纯出,不適合初創(chuàng)型公司以這樣的形式去設(shè)計項目蚯妇。

在前端里,領(lǐng)域驅(qū)動設(shè)計又意味著什么呢

很多時候暂筝,作為一個前端開發(fā)箩言,我們會以頁面作為最小顆粒,也就是在設(shè)計的時候焕襟,我們會認(rèn)為一個頁面就是一個 實體(實體可以理解為值對象的集合)陨收,一個menu的模塊,就是 聚合(聚合可以理解為實體的集合)鸵赖。在理解上面這兩個名詞之后务漩,我們從最小顆粒(頁面)開始看起。

頁面通常包含 N 個組件卫漫,在React或者Vue中,我們使用Ant Design或者ElementUi肾砂,這里我僅用React舉例列赎。

一個React的頁面Container,是一些Component的合集,我們把頁面的變化進(jìn)行了封裝包吝,因為我們認(rèn)為業(yè)務(wù)的變化會產(chǎn)生頁面的變化饼煞。這一點(diǎn)沒錯,但是诗越,相反的砖瞧,我們?nèi)ピ敿?xì)的說應(yīng)該叫 業(yè)務(wù)的變化會引起部分頁面中組件的變化,我們一概而論的把變化封裝在了更高一層的頁面上嚷狞,實際上就是沒有進(jìn)行良好的組件拆分块促。

那么我們繼續(xù)解耦,我們將每一個Component作為一個值對象去看床未,這樣在業(yè)務(wù)變化的時候竭翠,我們就可以進(jìn)一步的去修改特定的組件。

那么薇搁,領(lǐng)域驅(qū)動設(shè)計到此為止了嗎斋扰?

在我看來,這是開始啃洋。

從第二節(jié)看下來传货,通篇的文字都是業(yè)務(wù)的變化,這就是最大的問題宏娄。我們所有的設(shè)計问裕,都是基于業(yè)務(wù)。這并不符合DDD绝编,因為DDD是領(lǐng)域驅(qū)動設(shè)計僻澎,也就是在DDD看來,設(shè)計的根本是因為領(lǐng)域十饥。那么領(lǐng)域是如何去定義窟勃,我們就需要進(jìn)行探討了。

我們還是看一個比較常見的場景逗堵。


需求場景

在上面這個需求里秉氧,我們可以看到有SelectTable構(gòu)成的一個Component,如果我們將此Component作為值對象的話蜒秤,如果我Select區(qū)域要新增一些條件汁咏,或者Table需要有改動,進(jìn)行的修改作媚,都是需要在此Component上攘滩,所以,在DDD中纸泡,我認(rèn)為漂问,構(gòu)成的最小顆粒應(yīng)該是由 UI 庫提供的組件是值對象,而我們的Component級別的封裝應(yīng)該是 實體 ,構(gòu)成的頁面應(yīng)該是 聚合蚤假。

DDD的設(shè)計
// RecentSales.jsx
import Header from "./component/Header";
import Content from "./component/Content";

export default () => {
  return [
    <Header key="recentSalesHeader" />,
    <Content key="recentSalesContent" />
  ];
};
// ./component/Header/index.jsx
import Title from "./entity/Title";
import SelectTime from "./entity/SelectTime";

export default () => {
  return [<Title key="headerTitle" />, <SelectTime key="headerSelectTime" />];
};
// ./component/Header/entity/Title/index.jsx
import { Typography } from "antd";

const { Title, Text } = Typography;

export default () => {
  return [<Title key="titleTitle" />, <Text key="titleText" />];
};
// ./component/Header/entity/SelectTime/index.jsx
import { DatePicker } from "antd";

export default () => {
  return <DatePicker />;
};
// ./component/Content/index.jsx
import SalesTable from "./entity/SalesTable";

export default () => {
  return <SalesTable />;
};
// ./component/Content/entity/SalesTable/index.jsx
import { Table } from "antd";

export default () => {
  return <Table />;
};

講到這里栏饮,我希望你有所收獲,無論是你對DDD領(lǐng)域驅(qū)動設(shè)計的不屑一顧磷仰,還是你從中有了新的見解袍嬉。

之后,我要開始講一些 奇怪 的東西了灶平。

剛剛我們不斷的在說伺通,DDD是在進(jìn)行封裝最小變化,那么問題來了民逼,<Table />這樣的組件泵殴,具有可擴(kuò)展性嗎?所有的可拓展性拼苍,都是基于樣式層面的調(diào)整笑诅,如果我想對表格的渲染過程有不同的設(shè)計呢?如果我對表格的渲染需要惰性分頁疮鲫,滾動分頁呢吆你?你會發(fā)現(xiàn),并不支持俊犯,所以妇多,為什么中臺系統(tǒng)是ant design這類 UI 庫主打,是因為通用性極強(qiáng)燕侠,此類庫提供了“最佳”實踐者祖,特殊的需求要自己寫【钔看起來沒什么問題七问,但是在我看來,不具備闊拓展性茫舶。

所以我希望的械巡,或者我所設(shè)想的組件庫,應(yīng)該充分利用extends饶氏,達(dá)到如下的效果:

新設(shè)計

也就是我們不在自己構(gòu)建一個全新的值對象讥耗,而是在通用的基礎(chǔ)上,去繼承并極大的增加復(fù)用性疹启。

以上都是個人的一些見解啦古程,DDD是一個還在摸索階段的東西,來吧喊崖,關(guān)注 ihap 技術(shù)黑洞挣磨,我是 ihap肥少菲宴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市趋急,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌势誊,老刑警劉巖呜达,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異粟耻,居然都是意外死亡查近,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門挤忙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霜威,“玉大人,你說我怎么就攤上這事册烈「昶茫” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵赏僧,是天一觀的道長大猛。 經(jīng)常有香客問我,道長淀零,這世上最難降的妖魔是什么挽绩? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮驾中,結(jié)果婚禮上唉堪,老公的妹妹穿的比我還像新娘。我一直安慰自己肩民,他們只是感情好唠亚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著此改,像睡著了一般趾撵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上共啃,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天占调,我揣著相機(jī)與錄音,去河邊找鬼移剪。 笑死究珊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纵苛。 我是一名探鬼主播剿涮,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼言津,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了取试?” 一聲冷哼從身側(cè)響起悬槽,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞬浓,沒想到半個月后初婆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猿棉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年磅叛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萨赁。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡弊琴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杖爽,到底是詐尸還是另有隱情敲董,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布慰安,位于F島的核電站臣缀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏泻帮。R本人自食惡果不足惜精置,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锣杂。 院中可真熱鬧脂倦,春花似錦、人聲如沸元莫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踱蠢。三九已至火欧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茎截,已是汗流浹背苇侵。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留企锌,地道東北人榆浓。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像撕攒,于是被迫代替她去往敵國和親陡鹃。 傳聞我的和親對象是個殘疾皇子烘浦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348