別再搞三層架構(gòu)了!這 3 種 DDD 分層架構(gòu)的模式,不香嗎?

- 前言 -

- DDD 的基本概念 -
微服務(wù)中應(yīng)該首先建立UL,然后再討論領(lǐng)域模型。 一個(gè)微服務(wù)最大不要超過一個(gè)BC,否則微服務(wù)內(nèi)會(huì)存在有歧義的領(lǐng)域概念。 一個(gè)微服務(wù)最小不要小于一個(gè)聚合,否則會(huì)引入分布式事務(wù)的復(fù)雜度。 微服務(wù)的劃分過程類似于BC的劃分過程,每個(gè)微服務(wù)都有一個(gè)領(lǐng)域模型。 微服務(wù)間的集成可以通過Context Map來完成,比如ACL(Anticorruption Layer,防腐層)。 微服務(wù)間最好采用Domain Event(領(lǐng)域事件)來進(jìn)行交互,使得微服務(wù)可以保持松耦合。 ……

- 分層架構(gòu) -
1. 開發(fā)人員可以只關(guān)注整個(gè)結(jié)構(gòu)中的某一層。 2. 可以很容易的用新的實(shí)現(xiàn)來替換原有層次的實(shí)現(xiàn)。 3. 可以降低層與層之間的依賴。 4. 有利于標(biāo)準(zhǔn)化。 5. 利于各層邏輯的復(fù)用。
1. 降低了系統(tǒng)的性能。這是顯然的,因?yàn)樵黾恿酥虚g層,不過可以通過緩存機(jī)制來改善。 2. 可能會(huì)導(dǎo)致級(jí)聯(lián)的修改。這種修改尤其體現(xiàn)在自上而下的方向,不過可以通過依賴倒置來改善。

- 模式一:四層架構(gòu) -

1. User Interface為用戶界面層(或表示層),負(fù)責(zé)向用戶顯示信息和解釋用戶命令。這里指的用戶可以是另一個(gè)計(jì)算機(jī)系統(tǒng),不一定是使用用戶界面的人。 2. Application為應(yīng)用層,定義軟件要完成的任務(wù),并且指揮表達(dá)領(lǐng)域概念的對(duì)象來解決問題。這一層所負(fù)責(zé)的工作對(duì)業(yè)務(wù)來說意義重大,也是與其它系統(tǒng)的應(yīng)用層進(jìn)行交互的必要渠道。應(yīng)用層要盡量簡(jiǎn)單,不包含業(yè)務(wù)規(guī)則或者知識(shí),而只為下一層中的領(lǐng)域?qū)ο髤f(xié)調(diào)任務(wù),分配工作,使它們互相協(xié)作。它沒有反映業(yè)務(wù)情況的狀態(tài),但是卻可以具有另外一種狀態(tài),為用戶或程序顯示某個(gè)任務(wù)的進(jìn)度。 3. Domain為領(lǐng)域?qū)樱ɑ蚰P蛯樱?,?fù)責(zé)表達(dá)業(yè)務(wù)概念,業(yè)務(wù)狀態(tài)信息以及業(yè)務(wù)規(guī)則。盡管保存業(yè)務(wù)狀態(tài)的技術(shù)細(xì)節(jié)是由基礎(chǔ)設(shè)施層實(shí)現(xiàn)的,但是反映業(yè)務(wù)情況的狀態(tài)是由本層控制并且使用的。領(lǐng)域?qū)邮菢I(yè)務(wù)軟件的核心,領(lǐng)域模型位于這一層。 4. Infrastructure層為基礎(chǔ)實(shí)施層,向其他層提供通用的技術(shù)能力:為應(yīng)用層傳遞消息,為領(lǐng)域?qū)犹峁┏志没瘷C(jī)制,為用戶界面層繪制屏幕組件,等等。基礎(chǔ)設(shè)施層還能夠通過架構(gòu)框架來支持四個(gè)層次間的交互模式。傳統(tǒng)的四層架構(gòu)都是 限定型松散分層架構(gòu) ,即Infrastructure層的任意上層都可以訪問該層(“L”型),而其它層遵守 嚴(yán)格分層架構(gòu)
1. User Interface層主要是Restful消息處理,配置文件解析,等等。 2. Application層主要是多進(jìn)程管理及調(diào)度,多線程管理及調(diào)度,多協(xié)程調(diào)度和狀態(tài)機(jī)管理,等等。 3. Domain層主要是領(lǐng)域模型的實(shí)現(xiàn),包括領(lǐng)域?qū)ο蟮拇_立,這些對(duì)象的生命周期管理及關(guān)系,領(lǐng)域服務(wù)的定義,領(lǐng)域事件的發(fā)布,等等。 4. Infrastructure層主要是業(yè)務(wù)平臺(tái),編程框架,第三方庫(kù)的封裝,基礎(chǔ)算法,等等。

- 模式二:五層架構(gòu) -
傳統(tǒng)上,面向?qū)ο缶幊陶Z言拿不出辦法去捕捉對(duì)象之間的協(xié)作,反映不了協(xié)作中往來的算法。就像對(duì)象的實(shí)例反映出領(lǐng)域結(jié)構(gòu)一樣,對(duì)象的協(xié)作與交互同樣是有結(jié)構(gòu)的。協(xié)作與交互也是最終用戶心智模型的組成部分,但你在代碼中找不到一個(gè)內(nèi)聚的表現(xiàn)形式去代表它們。在本質(zhì)上,角色體現(xiàn)的是一般化的、抽象的算法。角色沒有血肉,并不能做實(shí)際的事情,歸根結(jié)底工作還是落在對(duì)象的頭上,而對(duì)象本身還擔(dān)負(fù)著體現(xiàn)領(lǐng)域模型的責(zé)任。
1. Data層描述系統(tǒng)有哪些領(lǐng)域概念及其之間的關(guān)系,該層專注于領(lǐng)域?qū)ο蟮拇_立和這些對(duì)象的生命周期管理及關(guān)系,讓程序員站在對(duì)象的角度思考系統(tǒng),從而讓“系統(tǒng)是什么”更容易被理解。 2. Context層:是盡可能薄的一層。Context往往被實(shí)現(xiàn)得無狀態(tài),只是找到合適的role,讓role交互起來完成業(yè)務(wù)邏輯即可。但是簡(jiǎn)單并不代表不重要,顯示化context層正是為人去理解軟件業(yè)務(wù)流程提供切入點(diǎn)和主線。 3. Interactive層主要體現(xiàn)在對(duì)role的建模,role是每個(gè)context中復(fù)雜的業(yè)務(wù)邏輯的真正執(zhí)行者,體現(xiàn)“系統(tǒng)做什么”。role所做的是對(duì)行為進(jìn)行建模,它聯(lián)接了context和領(lǐng)域?qū)ο?。由于系統(tǒng)的行為是復(fù)雜且多變的,role使得系統(tǒng)將穩(wěn)定的領(lǐng)域模型層和多變的系統(tǒng)行為層進(jìn)行了分離,由role專注于對(duì)系統(tǒng)行為進(jìn)行建模。該層往往關(guān)注于系統(tǒng)的可擴(kuò)展性,更加貼近于軟件工程實(shí)踐,在面向?qū)ο笾懈嗟氖且灶惖囊暯沁M(jìn)行思考設(shè)計(jì)。 DCI目前廣泛被看作是對(duì)DDD的一種發(fā)展和補(bǔ)充,用在基于面向?qū)ο蟮念I(lǐng)域建模上。顯式的對(duì)role進(jìn)行建模,解決了面向?qū)ο蠼V械某溲P秃拓氀P椭疇?zhēng)。DCI通過顯式的用role對(duì)行為進(jìn)行建模,同時(shí)讓role在context中可以和對(duì)應(yīng)的領(lǐng)域?qū)ο筮M(jìn)行綁定(cast),從而既解決了數(shù)據(jù)邊界和行為邊界不一致的問題,也解決了領(lǐng)域?qū)ο笾袛?shù)據(jù)和行為高內(nèi)聚低耦合的問題。
面向?qū)ο蠼C媾R的一個(gè)棘手問題是數(shù)據(jù)邊界和行為邊界往往不一致。遵循模塊化的思想,我們通過類將行為和其緊密耦合的數(shù)據(jù)封裝在一起。但是在復(fù)雜的業(yè)務(wù)場(chǎng)景下,行為往往跨越多個(gè)領(lǐng)域?qū)ο?,這樣的行為如果放在某一個(gè)對(duì)象中必然會(huì)導(dǎo)致別的對(duì)象需要向該對(duì)象暴漏其內(nèi)部狀態(tài)。所以面向?qū)ο蟀l(fā)展的后來,領(lǐng)域建模出現(xiàn)兩種派別之爭(zhēng),一種傾向于將跨越多個(gè)領(lǐng)域?qū)ο蟮男袨榻T陬I(lǐng)域服務(wù)中。如果這種做法使用過度,則會(huì)導(dǎo)致領(lǐng)域?qū)ο笞兂芍惶峁┮欢裧et方法的啞對(duì)象,這種建模結(jié)果被稱之為貧血模型。而另一派則堅(jiān)定的認(rèn)為方法應(yīng)該屬于領(lǐng)域?qū)ο?,所以所有的業(yè)務(wù)行為仍然被放在領(lǐng)域?qū)ο笾?,這樣導(dǎo)致領(lǐng)域?qū)ο箅S著支持的業(yè)務(wù)場(chǎng)景變多而變成上帝類,而且類內(nèi)部方法的抽象層次很難一致。另外由于行為邊界很難恰當(dāng),導(dǎo)致對(duì)象之間數(shù)據(jù)訪問關(guān)系也比較復(fù)雜,這種建模結(jié)果被稱之為充血模型。
人有多重角色,不同的角色履行的職責(zé)不同。
1. 作為父母:我們要給孩子講故事,陪他們玩游戲,哄它們睡覺。 2. 作為子女:我們要孝敬父母,聽取他們的人生建議。 3. 作為下屬:我們要服從上司的工作安排,并高質(zhì)量完成任務(wù)。 4. 作為上司:我們要安排下屬的工作,并進(jìn)行培養(yǎng)和激勵(lì)。 5. ……
這里人(大對(duì)象)聚合了多個(gè)角色(小類),人在某種場(chǎng)景下,只能扮演特定的角色:
1. 在孩子面前,我們是父母。 2. 在父母面前,我們是子女。 3. 在上司面前,我們是下屬。 4. 在下屬面前,我們是上司。 5. ……
1. Domain層只保留了DCI中的Data層和Interaction層,我們?cè)趯?shí)踐中通常將這兩層使用目錄隔離,即通過兩個(gè)目錄object和role來分離層Data和Interaction。

DCI中的Context層從Domain層上移變成Context層。
因此,DDD分層架構(gòu)模式就變成了五層,如下圖所示:

1. User Interface是用戶接口層,主要用于處理用戶發(fā)送的Restful請(qǐng)求和解析用戶輸入的配置文件等,并將信息傳遞給Application層的接口。 2. Application層是應(yīng)用層,負(fù)責(zé)多進(jìn)程管理及調(diào)度、多線程管理及調(diào)度、多協(xié)程調(diào)度和維護(hù)業(yè)務(wù)實(shí)例的狀態(tài)模型。當(dāng)調(diào)度層收到用戶接口層的請(qǐng)求后,委托Context層與本次業(yè)務(wù)相關(guān)的上下文進(jìn)行處理。 3. Context是環(huán)境層,以上下文為單位,將Domain層的領(lǐng)域?qū)ο骳ast成合適的role,讓role交互起來完成業(yè)務(wù)邏輯。 4. Domain層是領(lǐng)域?qū)?,定義領(lǐng)域模型,不僅包括領(lǐng)域?qū)ο蠹捌渲g關(guān)系的建模,還包括對(duì)象的角色role的顯式建模。 5. Infrastructure層是基礎(chǔ)實(shí)施層,為其他層提供通用的技術(shù)能力:業(yè)務(wù)平臺(tái),編程框架,持久化機(jī)制,消息機(jī)制,第三方庫(kù)的封裝,通用算法,等等。
1. Context層在面向控制面或管理面且消息交互比較多的系統(tǒng)中又分裂成兩層,即Context層和大Context層。 2. Context層處理單位為Action,對(duì)應(yīng)一條同步消息或異步消息。 3. 大Context層對(duì)應(yīng)一個(gè)事務(wù)處理,由一個(gè)Action序列組成,一般通過Transaction DSL實(shí)現(xiàn),所以我們習(xí)慣把大Context層叫做Transaction DSL層。 4. Application層在面向控制面或管理面且消息交互比較多的系統(tǒng)中經(jīng)常會(huì)做一些調(diào)度相關(guān)的工作,所以我們習(xí)慣把Application層叫做Scheduler層。

1. User Interface是用戶接口層,主要用于處理用戶發(fā)送的Restful請(qǐng)求和解析用戶輸入的配置文件等,并將信息傳遞給Scheduler層的接口。 2. Scheduler是調(diào)度層,負(fù)責(zé)多進(jìn)程管理及調(diào)度、多線程管理及調(diào)度、多協(xié)程調(diào)度和維護(hù)業(yè)務(wù)實(shí)例的狀態(tài)模型。當(dāng)調(diào)度層收到用戶接口層的請(qǐng)求后,委托Transaction層與本次操作相關(guān)的事務(wù)進(jìn)行處理。 3. Transaction是事務(wù)層,對(duì)應(yīng)一個(gè)業(yè)務(wù)流程,比如UE Attach,將多個(gè)同步消息或異步消息的處理序列組合成一個(gè)事務(wù),而且在大多場(chǎng)景下,都有選擇結(jié)構(gòu)。萬一事務(wù)執(zhí)行失敗,則立即進(jìn)行回滾。當(dāng)事務(wù)層收到調(diào)度層的請(qǐng)求后,委托Context層的Action進(jìn)行處理,常常還伴隨使用Context層的Specification(謂詞)進(jìn)行Action的選擇。 4. Context是環(huán)境層,以Action為單位,處理一條同步消息或異步消息,將Domain層的領(lǐng)域?qū)ο骳ast成合適的role,讓role交互起來完成業(yè)務(wù)邏輯。環(huán)境層通常也包括Specification的實(shí)現(xiàn),即通過Domain層的知識(shí)去完成一個(gè)條件判斷。 5. Domain層是領(lǐng)域?qū)樱x領(lǐng)域模型,不僅包括領(lǐng)域?qū)ο蠹捌渲g關(guān)系的建模,還包括對(duì)象的角色role的顯式建模。 6. Infrastructure層是基礎(chǔ)實(shí)施層,為其他層提供通用的技術(shù)能力:業(yè)務(wù)平臺(tái),編程框架,持久化機(jī)制,消息機(jī)制,第三方庫(kù)的封裝,通用算法,等等。

- 模式三:六邊形架構(gòu) -
依賴倒置原則由Robert C. Martin提出,正式定義為:
高層模塊不應(yīng)該依賴于底層模塊,兩者都應(yīng)該依賴于抽象。
抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。
Cockburn在2005年提出的,在這種架構(gòu)中,不同的客戶通過“平等”的方式與系統(tǒng)交互。需要新的客戶嗎?不是問題。只需要添加一個(gè)新的適配器將客戶輸入轉(zhuǎn)化成能被系統(tǒng)API所理解的參數(shù)就行。同時(shí),對(duì)于每種特定的輸出,都有一個(gè)新建的適配器負(fù)責(zé)完成相應(yīng)的轉(zhuǎn)化功能。

端口并沒有明確的定義,它是一個(gè)非常靈活的概念。無論采用哪種方式對(duì)端口進(jìn)行劃分,當(dāng)客戶請(qǐng)求到達(dá)時(shí),都應(yīng)該有相應(yīng)的適配器對(duì)輸入進(jìn)行轉(zhuǎn)化,然后端口將調(diào)用應(yīng)用程序的某個(gè)操作或者向應(yīng)用程序發(fā)送一個(gè)事件,控制權(quán)由此交給內(nèi)部區(qū)域。應(yīng)用程序通過公共API接收客戶請(qǐng)求,使用領(lǐng)域模型來處理請(qǐng)求。
我們?cè)趯?shí)際的項(xiàng)目開發(fā)中,不同層的組件可以同時(shí)開發(fā)。當(dāng)一個(gè)組件的功能明確后,就可以立即啟動(dòng)開發(fā)。由于該組件的用戶有多個(gè),并且這些用戶的側(cè)重點(diǎn)不同,所以需要提供多個(gè)不同的接口。同時(shí),這些用戶的認(rèn)識(shí)也是不斷深入的,可能會(huì)多次重構(gòu)相關(guān)的接口。于是,組件的多個(gè)用戶經(jīng)常會(huì)找組件的開發(fā)者討論這些問題,無形中降低了組件的開發(fā)效率。

- 六邊形架構(gòu)模式的演變 -
1. Jeffrey Palermo在2008年提出了 洋蔥架構(gòu) ,六邊形架構(gòu)是洋蔥架構(gòu)的一個(gè)超集。 2. Robert C. Martin在2012年提出了干凈架構(gòu)(Clean Architecture),這是六邊形架構(gòu)的一個(gè)變體。 3. Russ Miles在2013年提出了 Life Preserver 設(shè)計(jì),這是一種基于六邊形架構(gòu)的設(shè)計(jì)。

- 總結(jié) -
來源:
https://www.jianshu.com/p/a775836c7e25

評(píng)論
圖片
表情
