DDD 領(lǐng)域驅(qū)動決策規(guī)則樹服務(wù)架構(gòu)設(shè)計
前言介紹
在上一章節(jié)介紹了領(lǐng)域驅(qū)動設(shè)計的基本概念以及按照領(lǐng)域驅(qū)動設(shè)計的思想進行代碼分層,但是僅僅只是從一個簡單的分層結(jié)構(gòu)上依然沒法理解DDD以及如何去開發(fā)這樣的微服務(wù)。另外往往按照這樣分層后依然感覺和MVC也沒有什么差別,也沒有感受到帶來什么非常大的好處。那么問題出在哪呢?我個人覺得DDD學(xué)起來更像是一套指導(dǎo)思想,不斷的將學(xué)習(xí)者引入到領(lǐng)域觸發(fā)的思維中去,而這恰恰也是最難學(xué)習(xí)的地方。時而感覺會了,而實際開發(fā)中又不對,本來已經(jīng)拆解清晰了,但怎么又那么像MVC了。甚至懷疑自己,我在干嘛?
無論是DDD、MVC,他們更像是家里三居或者四局的格局,每一種格局方式都是為了更好的實現(xiàn)對應(yīng)架構(gòu)下的設(shè)計思想。但,不是說給你一個通用的架構(gòu)模式,你就能開發(fā)出干凈(高內(nèi)聚)、整潔(低耦合)、漂亮(模塊化)的代碼。這就像是你家住三居、他家也住三居,但是你們屋子的舒適情況就一樣嗎?{再有,你家里會把廁所安在廚房嗎?但你的代碼是否這么干過,不合理的擺放導(dǎo)致重構(gòu)延期。}
另外DDD之所以看著簡單但又不那么好落地,個人認(rèn)為很重要就是領(lǐng)域思想,DDD只是指導(dǎo)但是不能把互聯(lián)網(wǎng)天下每一個業(yè)務(wù)行為開發(fā)都拿出來舉例子給你看,每個領(lǐng)域需要設(shè)計。所以需要一些領(lǐng)域?qū)<遥a(chǎn)品+架構(gòu)+不是杠精的程序猿}來討論梳理,將業(yè)務(wù)形態(tài)設(shè)計出合理的架構(gòu)&代碼。
案例目標(biāo)
本案例通過一個商品下單規(guī)則的場景來進行演示DDD;
- 假設(shè)產(chǎn)品需求業(yè)務(wù)運行人員可以對不同的商品配置一些規(guī)則,這些規(guī)則可以滿足不同用戶類型可以下單不同商品。
- 另外一些行為規(guī)則是會隨著業(yè)務(wù)發(fā)展而增加或者變動的,所以不能寫死{寫死太嚇人了}。
- 數(shù)據(jù)庫的PO類不應(yīng)該被外部服務(wù)調(diào)用,這也是必須的。如果你開發(fā)過很多系統(tǒng),那么可能已經(jīng)吃過虧并意識到這個問題。
- 按照DDD思想我們嘗試需要設(shè)計一個規(guī)則引擎的服務(wù),通過給外部提供非常簡單的接口(application)來獲取最終結(jié)果。
- 通過這樣的案例可以很容易的感受到目前的四層架構(gòu)確實在實現(xiàn)DDD思想上有很多的幫助。
如圖;DDD分層結(jié)構(gòu) | 指導(dǎo)設(shè)計架構(gòu)
bugstack蟲洞棧 & 分層結(jié)構(gòu)
DDD思想 · 開發(fā)設(shè)計
通過領(lǐng)域驅(qū)動設(shè)計的思想,從領(lǐng)域知識中提取和劃分為一個一個的子領(lǐng)域(核心子域,通用子域,支撐子域),并在子領(lǐng)域上建立模型。那么在技術(shù)實現(xiàn)上就需要去支撐這種建模,以使我們的代碼模塊獨立、免污染、易于擴展。
在上面我們提到需要開發(fā)一個可擴展使用的規(guī)則樹,那么如果只是單純的一次性需求,最快的方式是if語句就搞定了。但是為了使這個領(lǐng)域服務(wù)具備良好的使用和擴展性,我們需要做些拆分,那么如下;
- 你是否想過系統(tǒng)在過濾過則的時候其實就像執(zhí)行一棵二叉樹一樣非左即右側(cè),每一條線上都有著執(zhí)行條件,通過判斷來達到最終的結(jié)果。
- 按照樹形結(jié)構(gòu)我們將定義出來四個類;樹、節(jié)點、果實、指向線(From-To),用于描述我們的規(guī)則行為。
- 再此基礎(chǔ)上需要實現(xiàn)一個邏輯定義與規(guī)則樹執(zhí)行引擎,通過統(tǒng)一的引擎服務(wù)來執(zhí)行我們每次配置好的規(guī)則樹。
如圖;領(lǐng)域開發(fā)設(shè)計服務(wù)
bugstack蟲洞棧 & 領(lǐng)域開發(fā)設(shè)計服務(wù)
工程模型
application應(yīng)用層
application/MallRuleService.java | 應(yīng)用層定義接口服務(wù),也可以適當(dāng)做簡單包裝
domain領(lǐng)域?qū)?/h2>
domain中有兩個領(lǐng)域服務(wù);規(guī)則樹信息領(lǐng)域、規(guī)則執(zhí)行領(lǐng)域,通過合理的抽象化來實現(xiàn)高內(nèi)聚、低耦合的模塊化服務(wù)
domain/service/MallRuleServiceImpl.java | 領(lǐng)域?qū)又械膕ervice來實現(xiàn)應(yīng)用層接口
domain/service/logic/LogicFilter.java | 邏輯決策定義
domain/service/engine/EngineFilter.java | 引擎執(zhí)行定義
infrastructure基礎(chǔ)層
1、實現(xiàn)領(lǐng)域?qū)觽}儲定義 2、數(shù)據(jù)庫操作為非業(yè)務(wù)屬性的功能操作 3、在倉儲實現(xiàn)層進行組合裝配DAO&Redis&Cache等
infrastructure/repository/RuleRepository.java
interfaces接口層
1、包裝應(yīng)用接口對外提供api 2、外部傳輸對象采用DTO類,主要為了避免內(nèi)部類被污染{不斷的迭代的需求會在類中增加很多字段} 3、目前依然是提供的Http服務(wù),如果提供的rpc服務(wù),將需要對外提供可引用jar
interfaces/DDDController.java
測試驗證
規(guī)則樹結(jié)構(gòu){數(shù)據(jù)庫轉(zhuǎn)Json} | 可自行定義
通過postman調(diào)用 | raw => json
查詢規(guī)則樹信息 測試接口:http://localhost:8080/api/tree/decisionRuleTree 請求參數(shù):{"treeId":10001}
微信公眾號:bugstack蟲洞棧 & 查詢規(guī)則樹信息
規(guī)則樹行為信息決策 測試接口:http://localhost:8080/api/tree/decisionRuleTree 請求參數(shù):{"treeId":10001}
微信公眾號:bugstack蟲洞棧 & 規(guī)則樹行為信息決策
綜上總結(jié)
- 以上模擬購物場景下的規(guī)則處理抽象為樹決策引擎,以達到獨立領(lǐng)域服務(wù)。另外決策服務(wù)可以使用drools,任何抽象并不一定永遠使用,不要拘泥于一種形式。
- 一些大型架構(gòu)設(shè)計往往不是換一個設(shè)計模型就能徹底提升效率,還是需要人員整體素質(zhì),這是一個不斷培養(yǎng)的過程。
- 領(lǐng)域驅(qū)動設(shè)計的思想并不只是教會程序猿寫代碼,也是非程序員以外的所有互聯(lián)網(wǎng)人員都適合學(xué)習(xí)的內(nèi)容。
- 家里住的舒適不舒適,并不一定取決于三居或者四居,大部分還是依賴于怎么對格局的布置。事必躬親、親力親為的精益求精之路,終究會讓你設(shè)計出更加合理的代碼。