領(lǐng)域驅(qū)動設(shè)計的提出也是為了解決軟件的復(fù)雜性。軟件的核心功能就是解決現(xiàn)實(shí)的領(lǐng)域問題纯赎,通過建模谦疾,然后通過軟件實(shí)現(xiàn),完成領(lǐng)域問題的自動化犬金。二軟件不同于其他行業(yè)的主要問題是軟件面對的領(lǐng)域問題是千差萬別的念恍,所以很難形成標(biāo)準(zhǔn)的模型來解決。因此DDD(領(lǐng)域驅(qū)動設(shè)計)的核心就是關(guān)注領(lǐng)域知識晚顷,通過對領(lǐng)域知識的理解峰伙,抽象,建模该默,實(shí)現(xiàn)瞳氓,最終完成軟件的設(shè)計。而不是關(guān)注軟件實(shí)現(xiàn)技術(shù)栓袖,架構(gòu)匣摘。就想提到設(shè)計模式的時候說的一句話,設(shè)計模式是自然而然的出現(xiàn)在了你的設(shè)計中裹刮,而不是為了使用而使用音榜。其本質(zhì)也是這個意思,當(dāng)你對你的問題能很好的抽象建模后必指,再按照面向?qū)ο蟮脑O(shè)計原則囊咏,通過面向?qū)ο蟮某橄螅^承,封裝的技術(shù)梅割,那么自然而然的就呈現(xiàn)出了設(shè)計模式的形式霜第。所以領(lǐng)域驅(qū)動設(shè)計的第一步就是要和領(lǐng)域?qū)<覝贤ǎ煜ゎI(lǐng)域知識户辞。所以第一步就是把領(lǐng)域知識通過圖泌类,用例,畫等方式模型化底燎,建立通用語言刃榨,通過模型和領(lǐng)域?qū)<医涣鳎@些最終到了設(shè)計階段双仍,也就是團(tuán)隊內(nèi)部的通用語言和對象枢希,服務(wù)等的命名。
模型和架構(gòu):
在領(lǐng)域驅(qū)動設(shè)計這本書中講了分層架構(gòu)朱沃,從上到下分成四層苞轿,UI層,application層逗物,Domain層搬卒,Infrastructure層,從上到下翎卓,上層可以依賴下層契邀,但是下層不能依賴上層,其目的還是要做到Domain層和Infrastructure和UI層的分離失暴,這樣可以單獨(dú)針對業(yè)務(wù)層建模坯门,方便測試,維護(hù)锐帜。而應(yīng)用層是很薄的一層田盈,用來協(xié)調(diào)應(yīng)用的活動,不包含業(yè)務(wù)邏輯缴阎,通過調(diào)用領(lǐng)域?qū)觼硗瓿梢恍I(yè)務(wù)流程允瞧。所以從這個劃分來看,Clear架構(gòu)蛮拔,六邊形架構(gòu)更能反應(yīng)這個思想述暂。
模型驅(qū)動設(shè)計:
Entities 實(shí)體,在整個系統(tǒng)的生命周期中都有唯一標(biāo)識的對象建炫,比如訂單畦韭,賬戶,等對象肛跌。系統(tǒng)需要給這種對象生成一個我唯一的ID艺配,所以這些對象需要持久化察郁,需要保存到repository中。
value object 值對象转唉,用來描述領(lǐng)域的特殊方面皮钠,且沒有標(biāo)識符的一個對象。值對象不像實(shí)體對象赠法,值對象是可以創(chuàng)建麦轰,銷毀,復(fù)制砖织,是需要依賴于實(shí)體對象款侵。比如地址。值對象的不變性侧纯,是值對象的一個重要特性新锈,就是說一個值對象創(chuàng)建以后就不能改變了。所以值對象一般只包含無副作函數(shù)眶熬,如果要改變值對象壕鹉,就重新生成一個,如果要獲取一個值對象聋涨,就返回一個clone的對象。這樣可以有效的避免了在聚合外部對值對象的修改造成值對象的改變负乡。避免了模型內(nèi)部的相互影響牍白。
service 服務(wù),是對領(lǐng)域中的一些行為的抽象抖棘,不同于技術(shù)框架中的服務(wù)茂腥。領(lǐng)域建模中,領(lǐng)域語言的名詞很容變成實(shí)體或值對象切省,一些動詞可以變成實(shí)體和值對象的行為最岗。但是一些行為很難附屬于對象。對于這種就可以定義為服務(wù)朝捆。服務(wù)的幾個特征:1.服務(wù)之星的操作涉及一個領(lǐng)域概念般渡,這個領(lǐng)域概念通常不屬于一個實(shí)體或值對象。2.被執(zhí)行的操作涉及到領(lǐng)域中的其他的對象芙盘。3.操作是無狀態(tài)的驯用。
aggregates 聚合,聚合是用來定義對象所有權(quán)和邊界的領(lǐng)域模式儒老,聚合是針對數(shù)據(jù)變化可以考慮成一個單元的一組相關(guān)的對象蝴乔,對外只暴露聚合根,聚合根是一個實(shí)體驮樊,如果邊界內(nèi)有其他的實(shí)體薇正,那么實(shí)體的標(biāo)識符是本地化的片酝,只在聚合內(nèi)有意義。因為聚合只有根對外暴露挖腰,所以很容通過聚合保持?jǐn)?shù)據(jù)的一致性和強(qiáng)化不變量雕沿。不變量是指在數(shù)據(jù)發(fā)生變化時必須維護(hù)的那些規(guī)則,通常數(shù)據(jù)庫中會遇到這些問題曙聂。聚合內(nèi)的其他對象都是通過從聚合根的導(dǎo)航獲取到的晦炊。
factory 工廠,工廠不是一個領(lǐng)域概念宁脊,是一個設(shè)計上的概念断国,是用來輔助領(lǐng)域?qū)ο髣?chuàng)建復(fù)雜的對象,把創(chuàng)建對象的復(fù)雜過程封裝起來榆苞。具體實(shí)現(xiàn)可以參考設(shè)計模式的工廠模式稳衬。
repository 資源庫,資源庫的目的是封裝所有獲取對象飲用所需要的邏輯坐漏,資源庫是作為一個全局的可訪問對象的存儲點(diǎn)而存在薄疚。解耦領(lǐng)域?qū)ο蠛突A(chǔ)設(shè)施。repository長和常用的ORM結(jié)合起來使用赊琳。
保持模型的一致性 — 在實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計那本書里面叫戰(zhàn)略設(shè)計
這部分主要解決大項目街夭,需要多個團(tuán)隊協(xié)作的情況下如何保證模型的一致性,多個團(tuán)隊協(xié)作的時候躏筏,信息的溝通傳遞成了最大的挑戰(zhàn)板丽,隨著項目的深入,對領(lǐng)域知識的理解也會更深入趁尼,或者新的需求的引入埃碱,原有的模型也可能需要重構(gòu)。這也是軟件工程一直以來的一個挑戰(zhàn)酥泞。比如一個類砚殿,在不同的場景或者業(yè)務(wù)中需要增加,刪除一些屬性芝囤,如果在夸團(tuán)隊協(xié)作時就回來帶很多不一致的問題似炎。所以講大的模型分解成幾個較小的獨(dú)立部分,只要遵守相互綁定的契約悯姊,整合的好的小模型就會越來越獨(dú)立名党。這也是DDD被越來越多的和微服務(wù)結(jié)合起來的原因。
context 限界上下文挠轴,模型的上下文是一個條件集合传睹,用這些條件可以確保應(yīng)用在模型里的條款都有一個明確的含義。怎么理解呢岸晦,比如我們聽一句話的意思可能要放到上下文環(huán)境里面去理解欧啤,那么在領(lǐng)域建模的時候也是同樣睛藻,一個概念在不同的上下文中表達(dá)的意思,屬性是有些差別邢隧,比如某一個產(chǎn)品在現(xiàn)實(shí)給用戶的購買頁面和在庫存管理兩個不同的上下文就有不同的屬性店印。或者一個用戶在身份認(rèn)證上下文和購物上下文中就有不同倒慧,身份認(rèn)證更關(guān)注用戶的權(quán)限類型按摘,密碼。而購物上下文更關(guān)注的是什么等級纫谅,是不是金牌用戶炫贤。所以通過對上下文的劃分形成獨(dú)立的限界區(qū)域,由一個團(tuán)隊來負(fù)責(zé)一個限界上下文付秕,因為團(tuán)隊內(nèi)部可以保證充分的溝通兰珍,一個概念只需要在一個限界上下文中保持一致即可。在一個限界上下文中有一個統(tǒng)一語言询吴,用來在團(tuán)隊內(nèi)部溝通掠河。限界上下文之間通過良好的接口設(shè)計來協(xié)作。
context Map猛计,是指抽象出不同限界上下文和他們之間關(guān)系的文檔唠摹,可以是一個示圖。目的是讓每個在項目中工作的人都能看到并理解奉瘤≡灸郑可以考慮放到公共的區(qū)域,比如墻上毛好,白板上。
子系統(tǒng)之間的關(guān)系:
共享內(nèi)核 是指兩個團(tuán)隊統(tǒng)一共享的領(lǐng)域模型子集苛秕,共享內(nèi)核的目的是為了減少重復(fù)肌访,但是兩個團(tuán)隊維護(hù),所以要做到團(tuán)隊之間密切的交流艇劫,任何修改都要通知對方團(tuán)隊吼驶,而且要做到盡快的融合代碼。
客戶供應(yīng)商關(guān)系店煞, 兩個子系統(tǒng)蟹演,一個依賴另外一個。
防崩潰層顷蟀,在需要和一流軟件或其他獨(dú)立應(yīng)用集成時可以借用設(shè)計模式的facade和adapter模式來設(shè)計一個防腐層酒请。