今天我想與你聊一聊,DDD概念復(fù)雜、難懂,實(shí)際落地該怎么設(shè)計(jì)代碼實(shí)現(xiàn)模型。關(guān)于這個(gè)話題,先說說整體框架、思路,我打算結(jié)合兩部分分享給你,每一部分,相信仔細(xì)看完,都會或多或少有所收獲。以下內(nèi)容,預(yù)計(jì)1分鐘左右可快速看完:
前一部分,方法篇,旨在詳細(xì)介紹DDD所包含的幾個(gè)核心概念,以及圍繞這些概念所構(gòu)建的DDD代碼實(shí)現(xiàn)模型的組成結(jié)構(gòu)。
后半部分,實(shí)踐篇,進(jìn)一步思考。我繼續(xù)接著說,承接前面的內(nèi)容,要想讓這些代碼實(shí)現(xiàn)模型真正落地,我們需要把它們與具體的應(yīng)用場景結(jié)合起來。我將側(cè)重詳細(xì)闡述DDD代碼實(shí)現(xiàn)模型的設(shè)計(jì)方法,并給出一個(gè)具體的案例分析。
伴隨著業(yè)務(wù)系統(tǒng)復(fù)雜度的不斷提升,以及微服務(wù)架構(gòu)等分布式技術(shù)體系的大行其道,領(lǐng)域驅(qū)動設(shè)計(jì)(Domain Driven Design,DDD),日漸成為系統(tǒng)建模領(lǐng)域的主流設(shè)計(jì)思想和模式。在DDD中,引入了限界上下文、聚合、實(shí)體、值對象、領(lǐng)域事件、資源庫、應(yīng)用服務(wù)等一系列核心概念。
通過這些概念,開發(fā)人員可以開展系統(tǒng)設(shè)計(jì)和實(shí)現(xiàn)工作。但是,DDD中的這些概念相對都比較抽象,甚至有些晦澀難懂。再往相通或類似問題點(diǎn)上靠,我認(rèn)為實(shí)質(zhì)上對于復(fù)雜難懂的概念的理解和把握,我們一開始不必過于糾結(jié)這些概念本身,而是可以把它們與現(xiàn)實(shí)中的具體實(shí)現(xiàn)模型對應(yīng)起來。
通過兩者之間的合理映射,來促進(jìn)對概念本身的理解,如下圖所示。這里多說一句,即便你是其他技術(shù)領(lǐng)域的朋友,或許也曾遇到過類似問題,并有著共通性。希望看完今天的分享,可以或多或少幫助到你,并有所啟發(fā)、思考。
在上圖中,我們一方面嘗試把復(fù)雜概念映射到實(shí)現(xiàn)模型。另一方面,基于對實(shí)現(xiàn)模型的把握,可以反推對復(fù)雜概念的理解程度,從而更好地掌握這些概念。這也更足以見得實(shí)踐才能出真知,也只有設(shè)計(jì)過實(shí)現(xiàn)模型,才能真正掌握這些概念,從而把它們應(yīng)用到各種具體的場景中。
這是一種行之有效的辦法。
那么問題就來了,在日常開發(fā)過程中,如何確保DDD真正落地,把這些抽象概念轉(zhuǎn)為具體代碼模式,是我們今天要討論的內(nèi)容。
01
想設(shè)計(jì)代碼實(shí)現(xiàn)模型,咱非得了解DDD中這幾個(gè)核心概念?
總體來說,DDD提供的是一種開展業(yè)務(wù)建模和軟件設(shè)計(jì)的方法論。DDD認(rèn)為良好的系統(tǒng)架構(gòu),應(yīng)該是技術(shù)架構(gòu)和業(yè)務(wù)架構(gòu)相互融合的結(jié)果,開發(fā)人員不能脫離業(yè)務(wù)領(lǐng)域來設(shè)計(jì)技術(shù)架構(gòu)。為了實(shí)現(xiàn)這一目標(biāo),DDD提出了一組核心概念,如圖1所示。
我們先來看第一個(gè)核心概念,就比較難于理解,即限界上下文(Boundary Context)。在DDD中,當(dāng)我們把業(yè)務(wù)領(lǐng)域拆分成多個(gè)子域之后,限界上下文明確了子域的業(yè)務(wù)界限,并實(shí)現(xiàn)子域與子域之間的隔離,如圖2所示。
有了限界上下文,我們就需要圍繞業(yè)務(wù)場景設(shè)計(jì)領(lǐng)域模型對象(Domain Model Object)。領(lǐng)域模型對象,包含了豐富的業(yè)務(wù)邏輯和操作行為,這點(diǎn)和只包含數(shù)據(jù)屬性的傳統(tǒng)數(shù)據(jù)對象,有本質(zhì)區(qū)別。
因此,領(lǐng)域模型對象是我們在應(yīng)用DDD時(shí),最應(yīng)該關(guān)注的一組對象,也是最難把握的一組對象。
在DDD中,領(lǐng)域模型對象包括三大類,即聚合(Aggregate)、實(shí)體(Entity)和值對象(Value Object),這三類對象各有特點(diǎn)。
相較領(lǐng)域模型對象,領(lǐng)域事件誕生較晚,但也是領(lǐng)域模型的一個(gè)重要組成部分,因?yàn)楝F(xiàn)實(shí)中很多場景,都可以抽象成事件(Event),如圖4。
在DDD中,通過領(lǐng)域事件可以實(shí)現(xiàn)業(yè)務(wù)狀態(tài)變化的有效傳播,并在單個(gè)限界上下文內(nèi)部或在多個(gè)上下文之間,對這些狀態(tài)變化做出響應(yīng)。
業(yè)務(wù)領(lǐng)域中的各種狀態(tài)變化最終都需要進(jìn)行存儲。為此,DDD提供了一個(gè)針對業(yè)務(wù)數(shù)據(jù)的統(tǒng)一訪問入口,這就是資源庫(Repository)。通過資源庫,我們可以實(shí)現(xiàn)對各種領(lǐng)域?qū)ο蟮某志没僮鳎鐖D5所示。
最后,我們來引入應(yīng)用服務(wù)的概念。應(yīng)用服務(wù)包括命令(Command)服務(wù)和查詢(Query)服務(wù)兩大類,本質(zhì)上起到的是一種解耦和協(xié)調(diào)作用,確保各種領(lǐng)域模型對象之間的交互和協(xié)作。因此,在涉及到多個(gè)限界上下文之間的交互時(shí),我們需要重點(diǎn)關(guān)注應(yīng)用服務(wù)。如圖6所示。
02
概念復(fù)雜又難懂,想實(shí)際業(yè)務(wù)場景下真正落地,需引入DDD代碼實(shí)現(xiàn)模型
關(guān)于DDD中的核心概念,我就簡單介紹到這里,下一步就是要討論一個(gè)所有開發(fā)人員都必須面對的話題,即如何將這些復(fù)雜難懂的概念,在現(xiàn)實(shí)的開發(fā)過程中能夠真正落地?這就需要引入DDD代碼實(shí)現(xiàn)模型。
要想設(shè)計(jì)代碼實(shí)現(xiàn)模型,先得搞清楚它有哪幾部分組成?
無論設(shè)計(jì)方法有多好,能夠轉(zhuǎn)換為可運(yùn)行的代碼才是王道,這點(diǎn)對于DDD而言尤為如此。
可惜的是,目前業(yè)界關(guān)于如何實(shí)施這些概念,并沒有一套統(tǒng)一的標(biāo)準(zhǔn)和規(guī)范,這就導(dǎo)致我們在具體的開發(fā)過程中,常常感到無從下手。為此,本文專門提煉了一整套DDD代碼實(shí)現(xiàn)模型。接下來,讓我們從DDD代碼實(shí)現(xiàn)模型的基本概念和組織結(jié)構(gòu)展開討論。
在講代碼實(shí)現(xiàn)模型之前,先弄清楚什么是實(shí)現(xiàn)模型
說起模型(Model),業(yè)界主流的方法論認(rèn)為存在三種不同的類型,即領(lǐng)域模型、設(shè)計(jì)模型和代碼模型,如圖7所示。
關(guān)于領(lǐng)域模型,我們在前面的內(nèi)容中已經(jīng)做了介紹。在DDD中,聚合、實(shí)體、值對象、領(lǐng)域事件等,都可以歸屬到這一模型的范疇。
而設(shè)計(jì)模型(Design Model),可以分成邊界模型和內(nèi)部模型兩個(gè)組成部分。邊界模型明確系統(tǒng)邊界,抽象系統(tǒng)集成和交互方案。而內(nèi)部模型細(xì)化邊界模型,在明確系統(tǒng)邊界的前提下,實(shí)現(xiàn)系統(tǒng)內(nèi)部模塊和組件的抽象和構(gòu)建。因此,在DDD中,我們往往從限界上下文的角度出發(fā),來開展設(shè)計(jì)模型的建設(shè),如下圖所示。
最后,代碼模型為現(xiàn)實(shí)世界的解決方案,提供可執(zhí)行的系統(tǒng)環(huán)境。我們可以通過在領(lǐng)域模型和設(shè)計(jì)模型中嵌入代碼的方式來構(gòu)建代碼模型,該模型是將DDD各個(gè)復(fù)雜概念轉(zhuǎn)換為可執(zhí)行代碼的關(guān)鍵所在,也是我們今天要討論的主要內(nèi)容。
顯然,領(lǐng)域模型、設(shè)計(jì)模型和代碼模型之間,存在一種層次依賴關(guān)系,如圖9所示。
首先,領(lǐng)域模型代表領(lǐng)域的固有業(yè)務(wù);
設(shè)計(jì)模型指向領(lǐng)域模型,關(guān)注對外部接口的承諾以及交互關(guān)系;
代碼模型提供了完整實(shí)現(xiàn)過程,是對設(shè)計(jì)模型的細(xì)化。
正是通過這三種模型的整合,完成了從現(xiàn)實(shí)問題到最終能夠落地的實(shí)現(xiàn)方案的演進(jìn)。
DDD代碼實(shí)現(xiàn)模型,應(yīng)包含哪些部分?
針對DDD代碼實(shí)現(xiàn)模型的討論,我們也將遵循上述三種模型的整合過程。結(jié)合DDD中的各種核心概念,我們梳理DDD代碼實(shí)現(xiàn)模型組成結(jié)構(gòu),如圖10所示。
在上圖中,我們可以清晰看到DDD代碼實(shí)現(xiàn)模型的四個(gè)組成部分,分別面向領(lǐng)域?qū)ο?、?yīng)用服務(wù)、基礎(chǔ)設(shè)施以及上下文集成。講到這里,你可能會問,為什么我們要這樣設(shè)計(jì)DDD的代碼實(shí)現(xiàn)模型呢?
我們知道一個(gè)完整的DDD應(yīng)用程序,通常由多個(gè)限界上下文構(gòu)成。因此,對于代碼實(shí)現(xiàn)模型而言,我們需要重點(diǎn)考慮兩個(gè)維度,即:
- 單個(gè)限界上下文實(shí)現(xiàn)過程中的代碼模型
- 多個(gè)限界上下文之間集成過程中的代碼模型
在上圖中,關(guān)于領(lǐng)域?qū)ο?、?yīng)用服務(wù)、基礎(chǔ)設(shè)施代碼實(shí)現(xiàn)模型的討論,屬于單個(gè)限界上下文的范疇,而上下文實(shí)現(xiàn)代碼集成模型,顯然面向多個(gè)限界上下文,如圖11所示。
通過前面內(nèi)容的學(xué)習(xí),相信你對DDD代碼實(shí)現(xiàn)模型的組成結(jié)構(gòu),已了然在胸。
那么,在日常開發(fā)過程中,我們應(yīng)該如何設(shè)計(jì)這些代碼實(shí)現(xiàn)模型呢?有沒有具體的案例可以參考呢?這幾個(gè)問題點(diǎn),你可以先停下來琢磨下。
03 如何設(shè)計(jì)DDD代碼實(shí)現(xiàn)模型?
在分析DDD代碼實(shí)現(xiàn)模型時(shí),對于上一篇提到的四個(gè)組成部分,我們需要梳理它們的代碼結(jié)構(gòu)和依賴關(guān)系。針對代碼結(jié)構(gòu),我們需要明確代碼包的組成,以及內(nèi)部所包含的技術(shù)組件。
在明確了包結(jié)構(gòu)之后,依賴關(guān)系指的是我們需要進(jìn)一步明確這些代碼包和技術(shù)組件之間的交互關(guān)系?;谶@兩點(diǎn),讓我們先來討論領(lǐng)域?qū)ο蟮拇a實(shí)現(xiàn)模型。
領(lǐng)域?qū)ο蟠a實(shí)現(xiàn)模型
針對領(lǐng)域?qū)ο?,我們通常用“domain”這個(gè)單詞,對代碼包結(jié)構(gòu)的頂層包進(jìn)行命名,在該包結(jié)構(gòu)下的所有技術(shù)組件,都屬于領(lǐng)域?qū)ο蟮姆懂牎?/p>
具體而言,在DDD中,領(lǐng)域?qū)ο蟀I(lǐng)域模型對象、領(lǐng)域事件、資源庫以及應(yīng)用服務(wù)所涉及到的命令和查詢對象,其中領(lǐng)域模型對象可以分為聚合、實(shí)體和值對象這三大類。
因此,在DDD所有的代碼實(shí)現(xiàn)模型中,領(lǐng)域?qū)ο笊婕暗拇a結(jié)構(gòu)最為復(fù)雜,可以分成兩個(gè)層次,如圖1所示。
圖1
可以看到,這里的“domain”代表整個(gè)領(lǐng)域?qū)ο?,而“model”則代表領(lǐng)域模型對象,請注意這兩者在命名上的區(qū)別,以及它們之間的從屬關(guān)系。領(lǐng)域?qū)ο笫荄DD代碼實(shí)現(xiàn)模型的基礎(chǔ),包含核心業(yè)務(wù)邏輯的實(shí)現(xiàn)。
應(yīng)用服務(wù)代碼實(shí)現(xiàn)模型
類似地,針對應(yīng)用服務(wù),我們通常使用“application”來命名頂層包結(jié)構(gòu)。應(yīng)用服務(wù)包含查詢服務(wù)和命令服務(wù)這兩大類,所以在子包的命名上,也會用“commandservice”和“queryservice”加以區(qū)分,如圖2所示。
圖2
顯然,命令服務(wù)和查詢服務(wù),分別依賴于領(lǐng)域?qū)ο蟠a實(shí)現(xiàn)模型中的命令對象和查詢對象,我們用虛線表示這層依賴關(guān)系。在DDD的代碼實(shí)現(xiàn)模型中,應(yīng)用服務(wù)可以說是交互關(guān)系最為復(fù)雜的一個(gè)代碼模型。
一方面,它需要將命令和查詢操作,分派給聚合對象等領(lǐng)域模型對象。
另一方面,它也需要分別和基礎(chǔ)設(shè)施,以及其他限界上下文進(jìn)行交互。
關(guān)于后者,我們在討論到案例分析時(shí),還會做進(jìn)一步展開。
基礎(chǔ)設(shè)施代碼實(shí)現(xiàn)模型
其實(shí),所謂的基礎(chǔ)設(shè)施,指的是DDD應(yīng)用程序中所使用到的各種具體技術(shù)、工具和框架。常見的基礎(chǔ)設(shè)施類組件主要包括這幾個(gè)方面:
- 數(shù)據(jù)持久化(Persistence)
- 消息通信(Messaging)
- 系統(tǒng)配置(Config)
- 安全控制(Security)
因此,基礎(chǔ)設(shè)施的包結(jié)構(gòu)并不是固定的,而是根據(jù)具體的技術(shù)開發(fā)要求進(jìn)行靈活的組織,這里給出一個(gè)常見的包結(jié)構(gòu),如圖3所示。針對基礎(chǔ)設(shè)施,我們使用了“infrastructure”,對這一包結(jié)構(gòu)進(jìn)行命名。
圖3上圖中有一點(diǎn)需要注意,代表數(shù)據(jù)持久化的“persistence”包,和代表消息通信的“messaging”包,在基礎(chǔ)設(shè)施代碼實(shí)現(xiàn)模型中是最常見的,因?yàn)樗鼈兎謩e對應(yīng)著領(lǐng)域?qū)ο笾械馁Y源庫和領(lǐng)域事件。
在DDD中,資源庫和領(lǐng)域事件的定義位于領(lǐng)域?qū)ο蟠a實(shí)現(xiàn)模型中,它們與具體的實(shí)現(xiàn)技術(shù)無關(guān)。而與具體實(shí)現(xiàn)技術(shù)相關(guān)的持久化和消息通信,則位于基礎(chǔ)設(shè)施代碼實(shí)現(xiàn)模型中。這里體現(xiàn)了領(lǐng)域?qū)ο笈c實(shí)現(xiàn)技術(shù)相互分離的設(shè)計(jì)原則。
上下文集成代碼實(shí)現(xiàn)模型
最后,我們來討論上下文集成代碼實(shí)現(xiàn)模型。需要注意的是,這個(gè)模型實(shí)現(xiàn)起來難度最大,因?yàn)樯婕暗蕉喾N系統(tǒng)集成技術(shù)體系。
針對這一代碼實(shí)現(xiàn)模型,我們首先需要明確它是面向多個(gè)限界上下文的,所以我們需要考慮數(shù)據(jù)的流向,也就是所謂的內(nèi)向(Inbound)數(shù)據(jù)和外向(Outbound)數(shù)據(jù)。
一方面,限界上下文,需要暴露訪問入口供其他上下文進(jìn)行使用。站在當(dāng)前上下文角度看,這是一個(gè)Inbound操作。而當(dāng)某一個(gè)上下文向外部上下文發(fā)起請求時(shí),這就是一個(gè)Outbound操作,如圖4所示。
圖4
在代碼實(shí)現(xiàn)模型的設(shè)計(jì)上,我們也將采用“inbound”和“outbound”來命名包結(jié)構(gòu)。那么這兩個(gè)包結(jié)構(gòu)下,應(yīng)該包含哪些技術(shù)組件呢?
我們先來討論“outbound”包結(jié)構(gòu),如圖5所示。 圖中,“rest”包中的REST API將外部請求,轉(zhuǎn)化為內(nèi)部的Command和Query對象,并交由應(yīng)用服務(wù)進(jìn)行處理。在這個(gè)轉(zhuǎn)化過程中,通常需要引入專門的DTO(Data Transfer Object,數(shù)據(jù)傳輸對象)對象,和組裝器(Assembler)對象。
圖5
同時(shí),“eventpublisher”包中的事件發(fā)布器(Event Publisher),則用來面向外部限界上下文發(fā)布領(lǐng)域事件。
接著,我們討論“inbound”包結(jié)構(gòu)。在一個(gè)限界上下文中,數(shù)據(jù)的Inbound操作主要有兩類,一類是防腐層(Anti-Corruption Layer,ACL),用來向遠(yuǎn)程REST API發(fā)起請求并獲取結(jié)果。另一類是用來完成對領(lǐng)域事件進(jìn)行響應(yīng)的事件處理器(Event Handler),如圖6所示。
圖6
基于上下文集成過程,兩個(gè)上下文中的“inbound”和“outbound”包結(jié)構(gòu)中所包含的技術(shù)組件,實(shí)際上是一一對應(yīng)的,如圖7所示。
可以看到,一個(gè)限界上下文“inbound”中的“acl”和“eventhandler”,分別對應(yīng)著另一個(gè)限界上下文“outbound”中的“rest”和“eventpublisher”。
圖7
至此,關(guān)于DDD中四大類代碼實(shí)現(xiàn)模型,已介紹完。在接下來的內(nèi)容中,我們將基于一個(gè)具體的應(yīng)用場景,通過案例分析,將這些代碼實(shí)現(xiàn)模型付諸于實(shí)踐?;谶@個(gè)案例,你可以將本文前面介紹的所有內(nèi)容,和日常開發(fā)過程聯(lián)系起來,進(jìn)一步掌握將模型轉(zhuǎn)化為具體代碼的實(shí)現(xiàn)方法和技巧。
04 DDD代碼實(shí)現(xiàn)模型案例分析
在現(xiàn)實(shí)世界中,工單處理是一個(gè)非常常見的業(yè)務(wù)需求。而工單的發(fā)起,通常都是因?yàn)橛脩粜枰獙τ唵芜M(jìn)行咨詢或投訴。
在這個(gè)場景中,基于DDD的設(shè)計(jì)方法,我們可以分別拆分出工單(Ticket)、客服(Staff),以及訂單(Order)這三個(gè)限界上下文。在這三個(gè)上下文中,Ticket上下文,會分別與Staff和Order這兩個(gè)上下文進(jìn)行集成,從而創(chuàng)建工單申請,如圖8所示。
請注意,圖中展示了Ticket上下文,所具備的兩種不同的上下文集成方式。
針對Staff上下文,Ticket上下文將使用REST API,完成對工單中客服數(shù)據(jù)的獲取。
而針對Order上下文,則使用了領(lǐng)域事件,即一旦Order的狀態(tài)發(fā)生變化,Order上下文會發(fā)送對應(yīng)的領(lǐng)域事件到Ticket上下文中。
圖8
Ticket上下文代碼實(shí)現(xiàn)模型示例
顯然,針對這一場景,Ticket上下文同時(shí)具備了Inbound和Outbound操作。因此,它的代碼實(shí)現(xiàn)模型是最完整的,如圖9所示。
圖9
上圖中,我們使用IDEA這款開發(fā)工具和Spring Boot這一特定的開發(fā)框架,構(gòu)建了Ticket限界上下文的代碼實(shí)現(xiàn)模型。我們可以很清晰地看到,DDD四種代碼實(shí)現(xiàn)模型的表現(xiàn)形式,就是五個(gè)頂層的代碼包結(jié)構(gòu)。其中,上下文集成代碼實(shí)現(xiàn)模型同時(shí)包含了“inbound”和“outbound”這兩個(gè)代碼包。
我們再對這些頂層代碼包結(jié)構(gòu)做展開,可以得到如圖10所示的子代碼包結(jié)構(gòu)。
圖10(上下滑動查看)
上圖所示的所有子代碼包結(jié)構(gòu),在前面的內(nèi)容中也都已經(jīng)給出了相應(yīng)的描述,這里便不再贅述。
Ticket上下文中,命令服務(wù)TicketCommandService完成了對Staff服務(wù)的上下文集成,這時(shí)候采用的是防腐層ACL組件,示例代碼如下所示。
可以看到,這里使用AclStaffService這個(gè)ACL組件,對Staff服務(wù)發(fā)起了遠(yuǎn)程調(diào)用,然后把返回結(jié)果填充到命令對象,并創(chuàng)建Ticket聚合。最終,我們通過TicketRepository完成了對聚合對象的持久化操作。
圖11
上述AclStaffService,就完成了對Staff上下文所提供的REST API的調(diào)用,示例代碼如下所示。這里用到了Spring自帶的RestTemplate模板工具類,完成對遠(yuǎn)程HTTP端點(diǎn)的訪問操作。
圖12
Staff上下文代碼實(shí)現(xiàn)模型示例
在Staff上下文,我們需要完成對上述REST API的構(gòu)建,它的代碼工程結(jié)構(gòu)如下圖所示。
可以看到,相較Ticket上下文,Staff上下文的代碼結(jié)構(gòu)比較簡單,因?yàn)樵撋舷挛闹恍枰峁ν獾摹皁utbound”包,而基礎(chǔ)設(shè)施部分也只需要完成對領(lǐng)域?qū)ο蟮某志没僮骷纯伞?/p>
圖13
Order上下文代碼實(shí)現(xiàn)模型示例
最后,我們來到Order限界上下文,它的代碼實(shí)現(xiàn)模型是這樣的,可以一同看下。
圖14
我們知道Order上下文,提供了針對Order數(shù)據(jù)的領(lǐng)域事件發(fā)布機(jī)制,所以它的“outbound”包中包含了用于發(fā)布領(lǐng)域事件的“eventpublisher”子包,并提供了一個(gè)OrderEventPublisherService,如下所示。
圖15
這里通過Spring Cloud Stream,實(shí)現(xiàn)了領(lǐng)域事件的發(fā)布。而在Ticket上下文中,我們同樣可以基于Spring Cloud Stream,實(shí)現(xiàn)對該領(lǐng)域事件的監(jiān)聽和消費(fèi),示例代碼如下所示。
圖16
請注意,上述OrderUpdatedEventHandler,位于Ticket上下文“inbound”包的”eventhandler”子包中。
關(guān)于這些具體實(shí)現(xiàn)代碼的講解不是本文的重點(diǎn),你可以參考筆者在Github上的案例代碼進(jìn)行系統(tǒng)學(xué)習(xí):https://github.com/tianminzheng/customer-service。
05 總結(jié)和延伸思考
今天的分享到這里就結(jié)束了。本文內(nèi)容詳細(xì)回答了開發(fā)人員,在實(shí)現(xiàn)DDD應(yīng)用程序中所碰到的一個(gè)核心問題,即如何構(gòu)建DDD的代碼實(shí)現(xiàn)模型。之所以要討論這個(gè)話題,原因在于DDD中的很多概念都比較晦澀難懂,而業(yè)界也沒有為如何實(shí)現(xiàn)這些概念,提供統(tǒng)一的開發(fā)規(guī)范和標(biāo)準(zhǔn)。
而通過將DDD中的各種復(fù)雜概念與具體代碼實(shí)現(xiàn)模型進(jìn)行映射,在幫我們更好地理解這些概念的同時(shí),也能夠?qū)⑺鼈冎苯討?yīng)用到日常開發(fā)過程中。
通過本文內(nèi)容的介紹,開發(fā)人員可以結(jié)合自身的業(yè)務(wù)開發(fā)需求,設(shè)計(jì)一套完整的DDD代碼實(shí)現(xiàn)模型。這里也附上全文思維導(dǎo)圖,助你回顧、梳理思路等。
圖17 全文思維框架導(dǎo)圖-幫助你快速回顧、梳理、總結(jié)
最后,我覺得還是有必要強(qiáng)調(diào)一點(diǎn)
本文中給出的DDD代碼實(shí)現(xiàn)模型,也只是一個(gè)參考模型。而代碼實(shí)現(xiàn)模型的設(shè)計(jì),也與具體所采用的技術(shù)體系有一定關(guān)聯(lián)。在本文所展示的案例中,我們使用了Spring Boot、Spring Cloud Stream等Spring家族中的開發(fā)框架,來開發(fā)DDD應(yīng)用程序。
而如果你使用Axon這種基于事件溯源模式的DDD開發(fā)框架,那么在代碼實(shí)現(xiàn)模型中,就需要引入用于事件分發(fā)和存儲的Gateway、EventStore等組件,而位于基礎(chǔ)設(shè)施中的傳統(tǒng)數(shù)據(jù)持久化組件,可能就不一定會被使用到。
當(dāng)然,基于我們今天介紹的內(nèi)容,相信你并不難對這套DDD代碼實(shí)現(xiàn)模型進(jìn)行擴(kuò)展。DDD作為一種系統(tǒng)建模方法論,也存在一些諸如分層架構(gòu)、整潔架構(gòu)、六邊形架構(gòu)等多種架構(gòu)風(fēng)格。
針對每種架構(gòu)風(fēng)格,我們都需要設(shè)計(jì)對應(yīng)的代碼實(shí)現(xiàn)模型。
而基于本文中介紹的內(nèi)容,通過對DDD中各個(gè)核心概念與實(shí)現(xiàn)模型之間進(jìn)行合理的映射,我在文中提供了一套設(shè)計(jì)代碼實(shí)現(xiàn)模型的系統(tǒng)方法,從而幫助你可以應(yīng)對不同架構(gòu)風(fēng)格的實(shí)現(xiàn)要求。
這也是本文的核心價(jià)值所在。