領域驅動設計-聚合,一種極簡的思惟模式
引言
做爲IT技術產業飛速發展的產物,軟件工程學已經成爲當今時代很是重要的一個學科。做爲一名資深的軟件開發從業者,咱們須要學習的東西實際上已經遠遠超出了本來在大學教育階段所接受的知識深度和廣度,領域驅動設計更是如此。固然必須認可的是大學階段開了不少扇窗,直到今天才深入體會那些平時看起來絕不起眼的學科(如圖論、機率論、高等代數),實際上對軟件領域的影響已經遠遠超出了咱們的想象,例如,若是想作AI,沒有紮實的數學和圖論基礎,顯然只能成爲工具的使用者,而非技術專家。html
有許多讀者提到,筆者的內容缺少實際例子,在具體閱讀時,很難造成帶入感。主要是由於領域驅動設計思想自己體系龐大,細節很是多,這須要在平常學習之餘多加思考,細細的品味知識中的奧妙,筆者也是按照一樣的思路來指導本身的學習過程的。坦率而言,要把這些概念的名詞都記住,顯然很容易,可是要理解這些名詞的具體含義以及實際應用場景,卻須要更多的思考,這也一樣是軟件工程博大精深的奧妙所在。數據庫
領域生命週期的複雜性是如何影響設計的
咱們都清楚領域驅動設計,做爲應對複雜情形下的軟件工程思路,實際上受到了傳統軟件思惟的普遍影響,例如以前提到的實體和值對象、以及服務和包(模塊)實際上在非領域驅動設計中一樣廣泛存在。可是聚合和聚合根的思想,應該屬於領域驅動設計中獨特的知識點,進一步增強這個知識點的認識,將有助於咱們更好的進行聚合設計,從而更好的設計一個符合實際應用場景的應用系統。 微信
在上一篇文章中,咱們瞭解到,領域驅動的五個基本部分(關聯,實體,值對象,服務和模塊),他們是構成軟件體系的最基礎元素。在一個簡單的軟件系統中,每每只需使用這些元素的簡單組合便可完成單個模塊功能的開發,並且顯然速度很是迅速。可是咱們也將一樣面對一些對象,他們具備更長的生命週期,也許有至關一部分時間,是經過複雜的數據持久化處理機制、甚至是跨數據源、跨服務來完成,這意味着不是單純的依靠一塊內存空間來度過的。它們與其餘對象有着複雜的依賴關係,在它們漫長的生命週期中,會根據不一樣場景的規則、經歷許屢次狀態的變化。對於這些對象的操做,稍不留心,就會致使代碼間的耦合度急劇提高,甚至成爲軟件系統中最難以維護的代碼塊,這實際上偏離了模型驅動設計的理想軌道,成爲經驗設計史上的一大典型問題。併發
領域驅動設計認爲,這種複雜過程的操做對模型驅動設計帶來的影響主要包括如下兩個方面: 工具
一、維護對象間,在整個生命週期中的完整性:對象依賴不一樣的數據源或存儲機制或內存單元時,完整性將難以保障。學習
二、陷入管理生命週期複雜性形成的困境中。同上,要維護這套具備複雜體系的模型結果,自己成爲一個問題。ui
聚合,讓設計簡化
領域驅動設計思想針對這兩種場景,設計了聚合(Aggregate)對象來解決這個問題,並使用工廠對象和倉儲對象來對生命週期進行管理,因爲時間和篇幅的關係,我這一篇先介紹聚合對象和聚合根,下一篇在介紹工廠對象和倉儲對象。url
實際上咱們很容易就設計出一個具備複雜關係的對象,例如,Person對象,實際上可能關聯了地址和工做等不一樣的實體或者值對象,若是要對數據進行刪除,可能傾向於直接刪除Person對象,而保留其餘對象;或者刪除Person對象時,同時刪除地址對象。可是這兩種方式都並不是很是合理的策略,在於方式一,會在數據庫中造成冗餘數據,不利於後期數據的維護管理;然後者則可能致使依賴於地址的其餘Person出現異常。spa
即便是再簡單的場景,遇到併發訪問時,也會存在問題。因爲不一樣的用戶對系統中的數據的訪問是隨機分佈的,意味着有可能會形成多個用戶同時修改相互依賴的對象,進而形成系統可用性的急劇降低。.net
所以,在具備複雜關聯的模型中,要想保證數據更改的一致性是很困難的。不只互不關聯的對象須要遵照必定的規則,並且緊密關聯的對象間操做一樣也存在規則。常用的一種方式多是事務鎖,可是設計謹慎的鎖機制,當然能夠解決這個問題,可是可能致使用戶間的操做不可控,系統變得不可用。事實上數據庫層面的行鎖和表鎖,也是爲了解決這些問題提供的思路,可是這種方案實際上分散了人們對於模型的注意力,使得系統流程的設計過程自己就至關臃腫。這也是古老的系統用戶體驗不佳的一個主要緣由。
領域驅動設計認爲,表面上看是對數據操做層面的技術問題,可是它的根源依然是因爲模型的設計依然是基於實體關係模型的設計,而缺少明肯定義的邊界。認爲經過一個合理的模型的設計,能夠是模型更加理解,而且使設計過程更易於溝通。當模型被修改時,它也將引導咱們對實現進行修改。
這種模式,就是聚合模式(Aggregate)。這種來源於製造業體系中的模型,簡單但嚴格,可是能夠提供新的思路。
領域驅動設計中,認爲實現這個聚合模型,應當包含如下要素:
一、經過一個頂層抽象來封裝模型中的引用。使用Aggregate對象,實現一組相關對象的集合,做爲數據修改的單元。
二、每一個Aggreate對象具備一個根和邊界。邊界,用以定義Aggreate內部都有什麼。而根是Aggregate對外暴露的特定實體。對Aggregate而言,外部對象只能夠引用根,而邊界內部的對象則能夠相互引用。
三、除根以外的全部實體,在Aggregate內部都有惟一標識,但外部對象只能看到根實體而沒法看到其餘實體。
對Aggregate的操做,應該按照必定的規則,確保數據變化時,可以保持一致性。而任何跨越Aggregate的規則,則不要求每時每刻都保持最新狀態,跨越經過事件處理、批處理或者其餘更新機制,使依賴項在規定的時間內獲得解決。可是在Aggregate內部,規則必須獲得知足。
這意味着,對於這個Aggregate的操做,必須應用更加具體的規則,包括但不限定於如下內容。
1、聚合根Entity,具備全局標識,表明整個Aggregate對外提供服務,並最終負責檢查規則。
2、邊界內的對象具備本地標識,但僅限於Aggregate內部保持惟一性。
3、Aggregate外部的對象不能引用除根Entity以外的其餘內部對象。根能夠將內部對象的引用傳遞給外部對象,可是外部對象只能使用,而不能保持引用更不能操做。這也意味着,根能夠將值對象的副本傳遞給外部對象,由於它只是一個屬性值,而不是一個完整的生命週期對象。
4、只有Aggregate的對象才能經過數據庫查詢直接完成,而其餘對象應該在建立後,經過根的對象遍歷關聯來發現。
5、Aggregate內部對象,能夠引用外部的Aggregate根對象的引用(不能反過來)
6、刪除操做,應該一次性刪除Aggregate邊界內的全部對象。
7、對Aggregate內部任何對象的操做,必須保證上述規則都獲得知足。
總結
Aggregate對象其實是經過劃分一個界限清晰的範圍,確保在Aggregate對象的生命週期內,對範圍內對象每一個階段的操做都知足規定規則。
對Aggregate對象的定義和分析是一件很是細緻的工做,咱們應該根據實際應用場景,將實體和值對象分別彙集到Aggregate中,定義好邊界和根後,經過根Entity來控制對邊界內部其餘對象的訪問。只容許外部對象引用根,並在一次操做中,臨時引用內部成員。但不能經過根來修改內部對象,這種設計有利於Aggregate內部的對象知足規則,也能保證它自己可以做爲一個總體知足規則。而對Aggregate對象上的操做,是經過下一篇提到的Factory和Repository來實現的,它們分別在不一樣的階段,實現了對象轉化的複雜性封裝。
原文地址:https://www.cnblogs.com/xiyuanMore/p/10241827.html
.NET社區新聞,深度好文,歡迎訪問公衆號文章彙總 http://www.csharpkit.com
本文分享自微信公衆號 - dotNET跨平臺(opendotnet)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。