一、傳統(tǒng)分層架構(gòu)
分層架構(gòu)的一個(gè)重要原則是:每層只能與位于其下方的層發(fā)生耦合。
分層架構(gòu)分兩種:一種是嚴(yán)格分層架構(gòu),規(guī)定某層只能與直接位于其下方的層發(fā)生耦合;另一種是松散分層架構(gòu),允許任意上方層與任意下方層發(fā)生耦合。
下圖是一個(gè)典型的DDD傳統(tǒng)分層架構(gòu)。
以上分層架構(gòu)中各層都有自己的職責(zé):
用戶接口層負(fù)責(zé)處理用戶請(qǐng)求和用戶顯示;
應(yīng)用層實(shí)現(xiàn)不同業(yè)務(wù)場景下的用例或業(yè)務(wù)流程。其中應(yīng)用服務(wù)通常接收來自用戶接口層的請(qǐng)求,然后通過資源庫獲取聚合實(shí)例,最后執(zhí)行相應(yīng)的命令操作,如下示例:
// 應(yīng)用層的用例
public void cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 領(lǐng)域?qū)拥臉I(yè)務(wù)邏輯
order.cancel()
orderRepository.save(order);
}
領(lǐng)域?qū)?/strong>實(shí)現(xiàn)系統(tǒng)的核心業(yè)務(wù)邏輯,主要包含基于DDD業(yè)務(wù)建模產(chǎn)生的領(lǐng)域模型,這里的業(yè)務(wù)邏輯不同于應(yīng)用層中的業(yè)務(wù)流程,如上代碼示例;
基礎(chǔ)設(shè)施層為其它各層提供通用的技術(shù)和基礎(chǔ)服務(wù),比如數(shù)據(jù)持久化功能。
二、傳統(tǒng)分層架構(gòu)的問題
DDD中資源庫(Repository)用來獲取或持久化聚合,每個(gè)聚合都擁有一個(gè)對(duì)應(yīng)的資源庫。由此可見資源庫應(yīng)該和聚合位于同一層,資源庫接口定義應(yīng)該位于領(lǐng)域?qū)樱Y源庫接口實(shí)現(xiàn)需要依賴基礎(chǔ)設(shè)施層的持久化機(jī)制,此時(shí)資源庫接口實(shí)現(xiàn)放在哪一層對(duì)傳統(tǒng)分層架構(gòu)來說是個(gè)問題。
如果把資源庫接口實(shí)現(xiàn)放在基礎(chǔ)設(shè)施層,那么基礎(chǔ)設(shè)施層就會(huì)向上依賴領(lǐng)域?qū)?,這樣就違反了分層架構(gòu)的原則:每層只能與位于其下方的層發(fā)生耦合。
或者可以放在領(lǐng)域?qū)樱沁@樣會(huì)使領(lǐng)域?qū)右蕾嚁?shù)據(jù)持久化的實(shí)現(xiàn)細(xì)節(jié),導(dǎo)致領(lǐng)域?qū)硬辉偈且粋€(gè)穩(wěn)定層。
也可以放在應(yīng)用層,不過和放在領(lǐng)域?qū)訒?huì)有同樣的問題。
那有沒有更好的方式呢?
有,采用依賴倒置,打破分層架構(gòu)原則。
三、依賴倒置原則
依賴倒置(或依賴反轉(zhuǎn))原則(Dependency inversion principle,DIP),由Bob大叔提出,其定義如下:
高層模塊不應(yīng)該依賴于低層模塊,兩者都應(yīng)該依賴于抽象。 抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。
我們把資源庫接口實(shí)現(xiàn)放在基礎(chǔ)設(shè)施層,讓基礎(chǔ)設(shè)施層向上依賴領(lǐng)域?qū)印km然這樣違背了分層架構(gòu)原則,但是卻符合依賴倒置原則:領(lǐng)域?qū)樱ǜ邔幽K)不依賴基礎(chǔ)設(shè)施層(低層模塊),兩者都依賴于資源庫接口(抽象)。采用了依賴倒置后,同時(shí)調(diào)整下基礎(chǔ)設(shè)施層位置,此時(shí)分層架構(gòu)如下圖:
四、六邊形架構(gòu)
分層架構(gòu)采用依賴倒置原則后,實(shí)際上已經(jīng)不存在分層的概念了。無論是高層還是低層,都只依賴于抽象,好像把整個(gè)分層架構(gòu)給推平了一樣。推平后的分層架構(gòu)如下圖:
給推平的分層架構(gòu)補(bǔ)上左側(cè)對(duì)稱的另一半,其結(jié)果就類似六邊形架構(gòu),如下圖是六邊形架構(gòu)。
六邊形架構(gòu)也叫端口和適配器。在這種架構(gòu)中,針對(duì)系統(tǒng)輸入輸出的不同交互方式,比如http、rpc、mq、數(shù)據(jù)持久化等,都有與之對(duì)應(yīng)的適配器,適配器又通過應(yīng)用層API與內(nèi)部進(jìn)行交互。
六邊形架構(gòu)讓應(yīng)用程序能夠以一致的方式被用戶、程序、自動(dòng)化測(cè)試、批處理腳本所驅(qū)動(dòng),而且能夠讓應(yīng)用程序的邊界更加清晰。有關(guān)六邊形架構(gòu)的詳細(xì)信息可以查看 六邊形架構(gòu)原文翻譯
五、為什么不選擇整潔架構(gòu)?
整潔架構(gòu)是Bob大叔在其《架構(gòu)整潔之道》一書中,對(duì)六邊形架構(gòu)和其他類似架構(gòu)做了總結(jié)和抽象之后,提出的一種架構(gòu)設(shè)計(jì)理念。
書中總結(jié)出,六邊形架構(gòu)和其他類似架構(gòu)設(shè)計(jì)出來的系統(tǒng),都具有相同的特點(diǎn):
獨(dú)立于框架:這些系統(tǒng)的架構(gòu)并不依賴某個(gè)功能豐富的框架之中的某個(gè)函數(shù)。框架可以被當(dāng)成工具來使用,但不需要讓系統(tǒng)來適應(yīng)框架。 可被測(cè)試:這些系統(tǒng)的業(yè)務(wù)邏輯可以脫離UI、數(shù)據(jù)庫、Web服務(wù)以及其他的外部元素來進(jìn)行測(cè)試。 獨(dú)立于UI:這些系統(tǒng)的UI變更起來很容易,不需要修改其他的系統(tǒng)部分。 獨(dú)立于數(shù)據(jù)庫:我們可以輕易將這些系統(tǒng)使用的Oracle、SQL Server替換成Mongo、BigTable、CouchDB之類的數(shù)據(jù)庫。因 為業(yè)務(wù)邏輯與數(shù)據(jù)庫之間已經(jīng)完成了解耦。 獨(dú)立于任何外部機(jī)構(gòu):這些系統(tǒng)的業(yè)務(wù)邏輯并不需要知道任何其他外部接口的存在。
綜合以上所有架構(gòu)的設(shè)計(jì)理念,Bob大叔提出了整潔架構(gòu)設(shè)計(jì)理念,如下圖。
以上圖中同心圓分別代表了軟件系統(tǒng)的不同層次,通常越靠近中心,其所在的軟件層次就越高。
整潔架構(gòu)規(guī)定了層之間的依賴關(guān)系規(guī)則:內(nèi)層(高層)不依賴外層(低層),六邊形架構(gòu)層之間的依賴關(guān)系也遵從此規(guī)則。
至此可以認(rèn)為整潔架構(gòu)是一種架構(gòu)設(shè)計(jì)的指導(dǎo)思想,六邊形架構(gòu)是整潔架構(gòu)的一種具體的架構(gòu)設(shè)計(jì)。
六、總結(jié)
采用依賴倒置原則后的分層架構(gòu)和六邊形架構(gòu),實(shí)際上都符合整潔架構(gòu)設(shè)計(jì)理念。但是六邊形架構(gòu)中使用端口與適配器,讓應(yīng)用程序能夠以一致的方式被用戶、程序、自動(dòng)化測(cè)試、批處理腳本所驅(qū)動(dòng),同時(shí)能夠讓應(yīng)用程序邊界更加清晰,從而能更好地防止領(lǐng)域?qū)雍蛻?yīng)用層邏輯泄露到外層。
七、參考
1.《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》
2.《架構(gòu)整潔之道》
作者:京東零售 加文雄文章來源:http://www.zghlxwxcb.cn/news/detail-591042.html
來源:京東云開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-591042.html
到了這里,關(guān)于DDD架構(gòu)為什么應(yīng)該首選六邊形架構(gòu)?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!