由不同部分組成
用於特定目的
抽象的系統
認知工具
模型有幾種表現方法(語言、代碼、圖解)
一個系統包含若干模型
通用語言是作爲領域專家與軟件專家之間的協作而演進的。
從以數據庫爲中心,過渡到以領域模型爲中心(可以更加純粹地使用面向對象技術)。
解決方案輪廓:
另一個維度:
領域模型不是特殊的圖,而是圖所要傳達的思想。
不只是領域專家頭腦中的知識,而是對這類知識嚴格地組織,和有選擇的抽象。
圖可以表示或者傳達模型,文字也可以。
不是要建立符合現實的模型,而是概括地反映現實。
模型在領域驅動設計中的作用:
知識消化不是孤立的活動,一般是在開發人員的領導下,由開發人員和領域專家組成的團隊來共同協作。
信息的原始資料來自領域專家頭腦中的知識,現有系統的用戶,以及技術團隊在相關遺留系統或者同領域的其他項目中積累的經驗。
模型聚焦於需求分析。與編程和設計緊密交互。
當我們的不再侷限於尋找實體和值對象時,我們才能充分吸取知識。因爲業務規則之間可能會存在不一致。
更明確的設計:
對象模型包括:屬性、關係、行爲和約束。
UML無法傳達模型的兩個重要方面,一是模型所表示的概念的意義,二是對象應該做哪些事情。
避免使用包羅萬象的對象模型圖。甚至不能使用包含所有細節的UML數據存儲庫。圖要簡單,只體現思想綱要。
任何參與建模的技術人員,不管在項目中的主要職責是什麼,都必須花時間瞭解代碼。
任何負責修改代碼的人則必須學會用代碼表達模型。
每一個開發人員都必須不同程度地參與模型討論並且你領域專家保持聯繫。
參與不同工作的人都必須有意識地通過UBIQUITOUS LANGUAGE與接觸代碼的人及時交換關於模型的想法。
分層:
每一層分別設計,內聚。
各層之間鬆散連接,層與層的依賴關係是單向的。上層可以使用或者操作下層。如果下層想與上層通信,可以使用回調或者OBSERVERS。
領域模型是一系列概念的集合。領域層的軟件構造反映了模型概念。
一個對象是用來表示某種具有連續性和標識的事物,還是用來描述某種狀態的屬性,是ENTITY和VALUE OBJECT之間的根本區別。
領域中還有一些方面適合用動作或者操作來表示,最好使用SERVICE。不要把操作的責任強加到ENTITY和VALUE OBJECT身上。SERVICE是應客戶端請求完成某事。
MODULE是模型的一部分,應該反映領域中的概念。
使關聯更容易控制:
ENTITY有特殊的建模和設計思路。他們有生命週期,這期間他們的形式和內容可能發生根本改變,但必須保持一種內在的連續性。
爲了跟蹤這些對象,必須定義他們的標識。
比如顏色就是VALUE OBJECT。
當我們只關心一個模型元素的屬性時,應該把它歸類爲VALUE OBJECT。應該使這個模型元素表示出其屬性的意義,併爲它提供相關功能。VALUE OBJECT應該是不可變的。不要爲它分配任何標識,而且不要把它設計成像ENTITY那麼複雜。
SERVICE的特徵:
SERVICE並不只是在領域層中使用,要注意區分領域層的SERVICE和其他層的SERVICE。
領域層和應用層的SERVICE和基礎設施層的SERVICE協作。應用層SERVICE和領域層SERVICE可能很難分清。
領域層的SERVICE要判斷是否滿足臨界值。
賬戶之間的轉賬屬於領域層SERVICE,因爲它含有重要的業務層規則。
將SERVICE劃分到各層中
SERVICE還有其他功能,可以控制領域層中接口的粒度,避免客戶端與ENTITY或者VALUE OBJECT耦合。
大型系統中,中等粒度的,無狀態的SERVICE更容易複用。因爲在簡單的接口背後封裝了重要的功能。
細粒度的對象可能導致分佈式的消息傳遞效率低下。
應用層負責對領域對象的行爲進行協調,因此,細粒度的領域對象可能會把領域層的知識泄漏到應用層中。這樣,應用層不得不處理複雜、細緻的交互。
MODULE是一個傳統的、較成熟的設計元素。
MODULE從更大的角度描述了領域。
MODULE應該是低耦合、高內聚的。
MODULE不僅僅是代碼的劃分,也是概念的劃分。
MODULE和較小的元素好像應該共同演變,實際上並不是這樣。MODULE被用來組織早期對象。在這之後,對象在變化時不脫離現有模塊定義的邊界。重構MODULE要比重構類做更多的工作,更有破壞性,不會很頻繁。
挑戰:
可以使用三種模式解決這些問題
FACTORY和REPOSITORY在AGGREGATE的基礎上操作,將特定生命週期轉換的複雜性封裝起來。
在具有複雜關聯的模型中,要保證對象更改的一致性是很難的。不僅互不關聯的對象需要遵守一些固定規則,而且緊密關聯的各組對象也要遵守一些固定規則。然而,過於謹慎的鎖定機制又會導致多個用戶之間的互相干擾,導致系統不可用。
模型中要有明確定義的邊界。
AGGREGATE就是一組相關對象的集合,把它作爲數據修改的單元。每個AGGREGATE都有一個ROOT和一個邊界。邊界定義了AGGREGATE內部有什麼。ROOT是AGGREGATE包含的一個特定ENTITY。對AGGREGATE而言,外部對象只能引用ROOT。而邊界內部的對象可以互相引用。除ROOT以外的其他ENTITY都有本地標識。比如汽車就是一個AGGREGATE。
固定規則(invariant)是指在數據變化時必須保持的一致性規則,其涉及AGGREGATE成員之間的內部關係。而任何跨越AGGREGATE的規則將不要求時刻保持最新狀態。通過事件處理、批處理或者其他更新機制,這些依賴會在一定時間內得以解決。但在每個事務完成時,AGGREGATE內部所應用的規則必須滿足。
只有ROOT纔可以直接通過數據庫查詢獲取。其他所有對象必須通過遍歷關聯來獲取。
應該將ENTITY和VALUE OBJECT分門別類地聚集到AGGREGATE中,並定義每個AGGREGATE的邊界。在每個AGGREGATE中,選擇一個ENTITY作爲ROOT。對內部成員的臨時引用可以被傳遞出去,但僅在一次操作中有效。由於ROOT控制訪問,因此不能繞過它修改內部對象。
AGGREGATE劃分出一個範圍,在這個範圍內,生命週期的每個階段都必須滿足一些固定規則。FACTORY和REPOSITORY都是在AGGREGATE之上執行操作。
當創建一個對象或整個AGGREGATE時,如果創建工作很複雜,或者暴露了過多內部結構,則使用FACTORY封裝。
應該將創建複雜對象的實例和AGGREGATE的職責轉移給單獨的對象,這個對象本身沒有承擔領域模型中的職責,但仍是領域設計的一部分。提供一個封裝所有複雜裝配的接口,這個接口不需要客戶引用要被實例化對象的具體類。在創建AGGREGATE時,要把它當作一個整體,並確保它滿足固定規則。
好的工廠要滿足兩個要求:
工廠和參數耦合。
由於VALUE OBJECT是不可變的,所以對應的工廠所生成的就是最終形式。
隨意的數據庫查詢會破壞領域對象的封裝和AGGREGATE。技術基礎設施和數據庫訪問機制的暴露會增加客戶的複雜度,並妨礙模型驅動的設計。
REPOSITORY將某種類型的所有對象表示爲一個概念集合(通常是模擬的),它的行爲類似集合,只是具有更復雜的查詢功能。在增加或刪除對應類型的對象時,REPOSITORY的後臺機制負責將對應的對象添加到數據庫中,或者從數據庫刪除。這個定義將一組緊密相關的職責集中在一起,這些職責提供了對AGGREGATE的ROOT的整個生命週期的全程訪問。
REPOSITORY的優點:
基於SPECIFICATION(規格)的查詢是將REPOSITORY通用化的好辦法。客戶可以使用規格來描述它需要什麼,而不用關心如何獲得結果。
也應該允許添加專門的硬編碼查詢。
將存儲、檢索和查詢機制封裝起來是REPOSITORY實現的最基本特徵。
並不意味着每個類都需要一個REPOSITORY。
REPOSITORY通常不提交事務。
從領域驅動設計的角度來看,FACTORY和REPOSITORY具有不同的職責:FACTORY負責製造新對象,REPOSITORY負責查找已有對象。REPOSITORY應該讓客戶感覺那些對象好像駐留在內存中一樣。對象可能必須被重建,但它是同一個概念對象,仍然處於生命週期的中間。
REPOSITORY也可以委託一個FACTORY來創建對象。
一般情況下,模型的精化、設計和實現應該在迭代開發過程中同步進行。