前言:為什么要用整篇文章來寫好像跟領(lǐng)域模型干系不大的《依賴倒置》呢羊初?因?yàn)椤兑蕾嚨怪谩肥橇呅渭軜?gòu)的核心滨溉!毫不夸張的說,不理解《依賴倒置》的程序員只能寫功能长赞,沒法寫出框架來晦攒!不論是依賴注入di或者依賴倒置dip,全部都是根據(jù)當(dāng)前成員變量的類型得哆,框架自動(dòng)注入實(shí)例的脯颜。區(qū)別在于成員變量是指針接收還是接口接收。具體如何自動(dòng)注入贩据,請(qǐng)看<<六邊形架構(gòu)>>和<<資源庫(kù)>>章節(jié)栋操。
一、如果不進(jìn)行依賴倒置會(huì)怎樣饱亮?
我們先看看什么是依賴倒置矾芙,教科書式的解釋就是:
- 高層模塊不應(yīng)依賴于低層模塊,二者應(yīng)依賴于抽象近上。
- 抽象不應(yīng)依賴于細(xì)節(jié)剔宪,細(xì)節(jié)應(yīng)依賴于抽象。
我們商品領(lǐng)域服務(wù)需要使用Repository
來持久化數(shù)據(jù)戈锻,中二代碼寫成這樣:
代碼示例
-
資源庫(kù)具體實(shí)現(xiàn)基礎(chǔ)設(shè)施(DB)的功能
-
領(lǐng)域模型依賴資源庫(kù)
-
領(lǐng)域模型直接使用以來的資源庫(kù)實(shí)現(xiàn)
這樣做的缺點(diǎn)是什么歼跟?
- 難以維護(hù)
內(nèi)部(領(lǐng)域模型)通常是業(yè)務(wù)邏輯和策略,這里就是DDD
里面的領(lǐng)域模型格遭,一個(gè)軟件區(qū)別于其他軟件的核心就在于業(yè)務(wù)邏輯和策略實(shí)現(xiàn)(也就是領(lǐng)域模型),而外部更多的是外部資源等基礎(chǔ)設(shè)施留瞳。PS:內(nèi)部外部概念可參考前文---《Golang領(lǐng)域模型-六邊形架構(gòu)》
如果領(lǐng)域模型依賴基礎(chǔ)設(shè)施拒迅,那就是業(yè)務(wù)邏輯依賴技術(shù)細(xì)節(jié),技術(shù)細(xì)節(jié)的改變將會(huì)對(duì)業(yè)務(wù)邏輯產(chǎn)生影響她倘,使其不得不改變璧微。這樣是不合理的。
- 復(fù)用困難
越核心的領(lǐng)域模型硬梁,復(fù)用價(jià)值越高前硫,如果對(duì)基礎(chǔ)設(shè)施進(jìn)行依賴,那么復(fù)用將會(huì)變得很困難荧止。
二屹电、如何進(jìn)行依賴倒置阶剑?
計(jì)算機(jī)科學(xué)中的所有問題都可以通過引入一個(gè)間接層得到解決。
All problems in computer science can be solved by another level of indirection
—— David Wheeler
實(shí)現(xiàn):domain
中引入dependency
包定義抽象層
代碼示例:
-
定義了商品倉(cāng)儲(chǔ)實(shí)現(xiàn)所需要滿足的接口危号。
商品領(lǐng)域服務(wù)成員變量直接引用抽象接口牧愁,框架負(fù)責(zé)依賴注入
- 商品領(lǐng)域模型中使用抽象出來的
GoodsRepo
方法
-
外部資源具體實(shí)現(xiàn)抽象接口
注意: var _ dependency.GoodsRepo = new(Goods)
我們用來檢查是否實(shí)現(xiàn)了接口
三艾凯、六邊形架構(gòu)核心-依賴倒置
前面講完基礎(chǔ)茫蛹,現(xiàn)在開始上大戲了迹炼!
為什么說六邊形架構(gòu)的核心是依賴倒置刀闷?
因?yàn)榱呅渭軜?gòu)不分高低層情连,而分內(nèi)外部幔嗦,嚴(yán)格的將基礎(chǔ)設(shè)施和領(lǐng)域模型分割開來锋恬。領(lǐng)域模型實(shí)現(xiàn)很簡(jiǎn)單桶蝎,但是將領(lǐng)域模型與DB声邦,Redis乏奥,MQ等基礎(chǔ)設(shè)施連接起來卻很困難。
如何連接翔忽?依賴倒置英融!
- main函數(shù)中安裝基礎(chǔ)設(shè)施kafka
- 實(shí)體中抽象領(lǐng)域事件接口
- kafka實(shí)現(xiàn)領(lǐng)域事件接口
- 訂單實(shí)體發(fā)送領(lǐng)域事件
依賴倒置的變與不變
通過第一、二小結(jié)概念的理解歇式,觀察第三小結(jié)的代碼驶悟。
Kafka是個(gè)優(yōu)秀的消息隊(duì)列中間件,它雖然很好材失,但只是基礎(chǔ)設(shè)施痕鳍,不是系統(tǒng)的核心部分,也許不久的某一天我們就會(huì)把它替換掉龙巨。亦或是替換掉別的中間件~
如果沒有依賴倒置怎么辦笼呆?
修改業(yè)務(wù)代碼?將所有用到過kafka的地方全部重新寫一遍旨别?下次有變化繼續(xù)寫诗赌?程序員聽了想打人!
有了依賴倒置怎么辦秸弛?
- 新的中間件只需要實(shí)現(xiàn)領(lǐng)域事件接口铭若。
- 在main中重新安裝。
這就是依賴倒置的魅力递览,沒有什么是不變的叼屠,重要的是將領(lǐng)域模型與基礎(chǔ)設(shè)施解耦開來。這樣替換只需要重寫領(lǐng)域事件绞铃,讓領(lǐng)域模型保持相對(duì)穩(wěn)定镜雨,不會(huì)隨著基礎(chǔ)設(shè)施的變化而被動(dòng)變化。
四儿捧、品一品
細(xì)品以上兩種代碼荚坞,第二種實(shí)現(xiàn)方式中挑宠,領(lǐng)域模型沒有像原來一樣直接依賴外部資源,而是將依賴關(guān)系“倒置”過來西剥,讓基礎(chǔ)設(shè)施去依賴由領(lǐng)域模型定義好的接口痹栖。
回前言所問,為什么要用一篇文章來解釋依賴倒置瞭空,這就是六邊形的核心揪阿,外部依賴內(nèi)部,內(nèi)部倒置基礎(chǔ)設(shè)施---freedom咆畏!
總結(jié)一下:
常用的實(shí)現(xiàn)方式是基礎(chǔ)設(shè)施有自己的接口南捂,領(lǐng)域模型依賴基礎(chǔ)設(shè)施提供的接口,比如基礎(chǔ)設(shè)施有自己的接口旧找,領(lǐng)域模型依賴基礎(chǔ)設(shè)施的接口溺健,這樣直接依賴的實(shí)現(xiàn)方式。
但是按照依賴倒置的原則钮蛛,接口的所有權(quán)是被倒置的鞭缭,表現(xiàn)在于接口是被領(lǐng)域模型的,領(lǐng)域模型擁有接口的所有權(quán)魏颓,基礎(chǔ)設(shè)施實(shí)現(xiàn)接口岭辣。這樣基礎(chǔ)設(shè)施的改動(dòng)不會(huì)影響領(lǐng)域模型,領(lǐng)域模型的復(fù)用不會(huì)依賴基礎(chǔ)設(shè)施甸饱。
1.依賴于構(gòu)建出來的抽象沦童,而不是具體類。
2.依賴倒置的關(guān)鍵是接口所有權(quán)的倒置叹话。
目錄
- golang領(lǐng)域模型-開篇
- golang領(lǐng)域模型-六邊形架構(gòu)
- golang領(lǐng)域模型-實(shí)體
- golang領(lǐng)域模型-資源庫(kù)
- golang領(lǐng)域模型-依賴倒置
- golang領(lǐng)域模型-聚合根
- golang領(lǐng)域模型-CQRS
- golang領(lǐng)域模型-領(lǐng)域事件
項(xiàng)目代碼 https://github.com/8treenet/freedom/tree/master/example/fshop
PS:關(guān)注公眾號(hào)《從菜鳥到大佬》偷遗,發(fā)送消息“加群”或“領(lǐng)域模型”,加入DDD交流群驼壶,一起切磋DDD與代碼的藝術(shù)氏豌!