一、聚合
上文講到的實體和值對象,都只是帶有業務邏輯的個體對象,表現的主要是個體屬性和行為。所以在領域模型中需要一個組織,有序的組織起個體的行為,將緊密關聯的個體對象聚集到一起,按照業務編排完成局部完整的業務邏輯。
比如在學生和老師都是帶有個體屬性和實體,都有各自的行為,是靠校長把老師和學生聚合到學校里,按照學校的規章制度,教學方針組織起了學校教育的工作,而組織里的各項制度,都是老師和學生需要遵守的。
多個聚合在同一個限界上下文和微服務內,在聚合中有個聚合根和上下文邊界,這個邊界比限界上下文要小,主要是根據業務的單一職責和高內聚設計原則,把涉及到這部分單一職責的實體和值對象聚合到一起,完成業務邏輯。
聚合在領域模型里是個業務邊界,沒有業務邏輯實現相關的代碼。
二、聚合根
比如人是一種對象,男人是一個家庭的根(聚合根),對這個家庭的女人,小孩的他有絕對保護權,想欺負女人和小孩都得先問問男人的拳頭,而男人,女人,小孩組成的家庭,就是一個聚合,男人就是這個聚合的聚合根
又比如淘寶是一個領域,在組織架構的聚合里,馬雲是這個聚合的老大,馬老板聚合了淘寶的業務,技術,產品,他就是這個聚合的聚合根,產品的思想,業務的發展,技術的投資,都是通過他點頭的。
聚合根和領域里的各種對象都是有各自獨立屬性的,比如男人的屬性(養家,買車,買房),女人(教育,生小孩,持家)同時他們是相互依賴,不可分離的,聚合根不能離開他的子對象,而領域里的子對象也不能離開他的聚合根,否則就玩不下去了
這樣設計的原因是:聚合內有一定業務規則以確保聚合內數據的一致性,如果在實現業務邏輯時,任由服務對聚合內實體數據進行修改,那么很可能會因為在數據變更過程中失去統一的業務規則控制,導致聚合內實體之間數據邏輯的不一致。
所以領域模型,就是我們先聊領域里聚合根和其他對象的屬性,關聯關系,再聊他們各自的行為,和可以干啥,他有哪些業務邏輯,邏輯方法。
三、聚合的特性
- 聚合根是實體,擁有實體的業務屬性和行為,同時也是聚合的管理者,負責協調聚合內的實體和值對象,按照固定的業務規則,完成業務邏輯。
- 聚合根是聚合對外唯一的接口人,聚合之間以聚合根ID關聯的方式接受聚合的外部任務和請求,聚合外不能通過對象引用的方式訪問聚合內的對象。需要將關聯的聚合根ID作為入參,先訪問聚合根,再通過聚合根導航到聚合內部實體。
- 如果聚合根被刪除了,他引用的實體和值對象就不會存在了
- 聚合根和聚合根所在層的領域服務都可以組合多個實體完成領域邏輯,但為了DDD分層架構的職責單一,聚合根最好只承擔聚合管理職能,只實現聚合內實體和聚合根本身相關的業務邏輯,而跨多個實體的復雜領域邏輯統一放到領域服務中實現。
- 領域建模中,可能存在一些獨立的找不到聚合根的實體,但可以根據高度依賴的業務邏輯,把這些實體集合也作為聚合處理。
四、聚合的設計

-
如圖,第一步首先采用事件風暴,梳理網購領域中的業務行為和行為產生的實體,值對象
- 從眾多實體中找到適合作為聚合對象管理者的根實體,即聚合根(圖中加深色的實體),我們可以根據這個實體是否貫穿整個軟件的生命周期,是否有全局唯一ID,是否可以作為一個聚合管理者去管理其他實體和值對象來確定是不是聚合根
- 將聚合根和關聯的實體,值對象匯聚到多個聚合里,如圖,用戶和訂單作為用戶聚合和訂單聚合的聚合根,匯聚了其他實體和值對象,形成用戶和訂單兩個聚合,划分好了聚合間的上下文。
- 找到聚合之間的引用,比如用戶數據冗余到了訂單聚合里的發件人和收件人,不至於用戶聚合發生異常時,訂單聚合也出現問題,訂單聚合記錄了發件人和收件人的快照數據
- 遍歷查看所有的聚合,看是否有與其他聚合相關的實體和值對象,遵循單一職責剝離出來歸並到其他聚合中
五、聚合的設計原則
《領域驅動設計》《基於DDD和微服務的中台架構與實現》一書中總結了聚合設計的原則
1、聚合內要有一套不變的,基本長期固化的業務規則,而不是簡單的將實體和值對象組合到一起,聚合的上下文邊界要清晰,保證聚合邊界外的任何東西與聚合無關
2、聚合可以作為拆分微服務的最小業務單元,與Serverless完美的結合,但不適合過度拆分,除非業務需求
3、聚合要高內聚,不宜設計得過大,會導致聚合內的實體和值對象膨脹從而不好管理
4、聚合間的交互要通過聚合根ID應用其他聚合
- 當領域模型隨着業務需求的變化,微服務內需要進行更小粒度的拆分,即聚合層面的拆分,這樣原本互相在微服務內互相依賴的聚合,就變成了服務間調用了,如果最開始在聚合內用對象應用的方式,那么服務拆分后就會失效,需要很大的代碼調整
- 采用聚合根ID應用的方式,則可以將聚合根ID和目標方法作為微服務的入參,實現跨微服務的調用,這種的改動方式會小很多,代碼理解起來也會更加的清晰
5、通過應用層實現領域服務的編排和組織,領域服務實現跨聚合的調用,組成業務邏輯
6、在聚合內使用數據強一致性,在聚合外使用數據最終一致性。DDD強調在一次事務中,最多只能修改一個聚合的數據。如果涉及到多個聚合的數據修改,在微服務內可以使用事件總線,微服務外使用領域事件驅動,通過消息的最終一致性來保證
參考書籍 ——《基於DDD和微服務的中台架構與實現》歐創新、鄧頔
參考書籍 ——《領域驅動設計》Eric Evans
參考書籍 ——《架構真經》Martin L. Abbott