聚合和聚合根是領域模型里面很重要的一個概念,其實我們在從真實世界對業務對象進行識別和概念建模的時候,關注的就是聚合根,這才是我們真正要管理的業務對象。一個對象可能有多個層次,也可能有多個子實體,但是這些子實體都不可能孤立存在,它們必須依附於一個聚合根存在,它們和根節點具有同樣的生命周期。
如果一個客戶消亡,客戶聯系方式,客戶的多張銀行賬戶信息將不再有任何意義。如果一張采購訂單頭消失,那么采購訂單明細沒有任何存在的意義。客戶,采購訂單,發票這些從真實業務中轉化過來的業務對象才是真正的領域核心對象。這些對象可能在領域建模的時候會分解到多個Entity或Value Object,但是一定要意識到實際的聚合在哪里?我們真正關注的業務對象實體究竟有哪些?
為什么如此強調領域模型,強調聚合根的概念,因此我們在關注領域模型的時候將有助於我們打破原有的關系型數據庫的思維模式,轉化為對象和領域的思維模式。可以看到領域建模和聚合根的思路正是既適合於關系型數據庫,也適合NoSql數據庫的建模思路。因為在NoSQL持久化的時候,我們看到采購訂單就是一個對象,其它明細和關聯信息都是這個對象下的子實體信息,采購訂單應該作為一個對象整體進行查詢和存儲,我們並不關系NoSQL會如何去存儲這個對象。讓我們正在關注領域對象,而不是去關心如何持久化。
聚合Aggregate就是一組相關對象的集合,我們把它作為數據修改和訪問的單元。每個聚合都會有一個聚合根和聚合的邊界Boundary,邊界定義了在一個聚合里面內部應該有哪些實體,哪些子實體對象。定義邊界的原因是我們期望對一個聚合的訪問是通過聚合根點進行的,聚合里面的子實體對外界是完全封閉的。對於外部對象不應該去訪問到一個聚合邊界里面的子實體。
在一些場景下,對於一個聚合的訪問,我們往往只需要查詢到頭信息,而不關心具體的子實體信息,這個有點類似於傳統O/R Mapping里面的惰性加載。在這里也必須要考慮到。在實現和設計聚合的時候,需要考慮到這種場景,即根據需要來加載一個完整聚合中的實體和子實體,以滿足性能的需要。如何對應關系型數據庫,對一個聚合實際的新增變更處理則可能涉及到多個數據表的多次操作,而這已經是倉儲接口和倉儲實現需要考慮的問題。現在對一個聚合的一次操作一定應該在一個完整的事務里面,以保障實際的事務完整性要求。
按實際對象分析思路,在領域模型中的領域對象分析應該按照從頂向下的思路進行展開,如果這樣的話首先識別到的就是聚合根對象,然后再考慮對聚合根對象進行展開,在聚合根對象的展開過程中進一步細化子實體之間的關聯和依賴關系。