每一個對象都有生命週期,如圖6-1所示。對象自建立後,可能會經歷各類不一樣的狀態,直至最終消亡——要麼存檔,要麼刪除。固然,不少對象是簡單的臨時對象,僅經過調用構造函數來建立,用來作一些計算,然後由垃圾收集器回收。這類對象不必搞得那麼複雜。但有些對象具備更長的生命週期,其中一部分時間不是在活動內存中度過的。它們與其餘對象具備複雜的相互依賴性。它們會經歷一些狀態變化,在變化時要遵照一些固定規則。管理這些對象時面臨諸多挑戰,稍有不慎就會偏離MODEL-DRIVEN DESIGN的軌道。數據庫
主要的挑戰有如下兩類。設計模式
(1) 在整個生命週期中維護完整性。併發
(2) 防止模型陷入管理生命週期複雜性形成的困境當中。框架
AGGREGATE(聚合),它經過定義清晰的所屬關係和邊界,並避免混亂、錯綜複雜的對象關係網來實現模型的內聚。聚合模式對於維護生命週期各個階段的完整性具備相當重要的做用。咱們將注意力轉移到生命週期的開始階段,使用FACTORY(工廠)來建立和重建複雜對象和AGGREGATE(聚合),從而封裝它們的內部結構。最後,在生命週期的中間和末尾使用REPOSITORY(存儲庫)來提供查找和檢索持久化對象並封裝龐大基礎設施的手段。數據庫設計
儘管REPOSITORY和FACTORY自己並非來源於領域,但它們在領域設計中扮演着重要的角色。這些結構提供了易於掌握的模型對象處理方式,使MODEL-DRIVEN DESIGN更完備。函數
使用AGGREGATE進行建模,而且在設計中結合使用FACTORY和REPOSITORY,這樣咱們就可以在模型對象的整個生命週期中,以有意義的單元、系統地操縱它們。AGGREGATE能夠劃分出一個範圍,這個範圍內的模型元素在生命週期各個階段都應該維護其固定規則。FACTORY和REPOSITORY在AGGREGATE基礎上進行操做,將特定生命週期轉換的複雜性封裝起來。測試
減小設計中的關聯有助於簡化對象之間的遍歷,並在某種程度上限制關係的急劇增多。但大多數業務領域中的對象都具備十分複雜的聯繫,以致於最終會造成很長、很深的對象引用路徑,咱們不得不在這個路徑上追蹤對象。在某種程度上,這種混亂狀態反映了現實世界,由於現實世界中就不多有清晰的邊界。但這倒是軟件設計中的一個重要問題。設計
假設咱們從數據庫中刪除一個Person對象。這我的的姓名、出生日期和工做描述要一塊兒被刪除,但要如何處理地址呢?可能還有其餘人住在同一地址。若是刪除了地址,那些Person對象將會引用一個被刪除的對象。若是保留地址,那麼垃圾地址在數據庫中會累積起來。雖然自動垃圾收集機制能夠清除垃圾地址,但這也只是一種技術上的修復;就算數據庫系統存在這種處理機制,一個基本的建模問題依然被忽略了。3d
即使是在考慮孤立的事務時,典型對象模型中的關係網也使咱們難以判定一個修改會產生哪些潛在的影響。僅僅由於存在依賴就更新系統中的每一個對象,這樣作是不現實的。對象
在多個客戶對相同對象進行併發訪問的系統中,這個問題更加突出。當不少用戶對系統中的對象進行查詢和更新時,必須防止他們同時修改互相依賴的對象。範圍錯誤將致使嚴重的後果。
在具備複雜關聯的模型中,要想保證對象更改的一致性是很困難的。不只互不關聯的對象須要遵照一些固定規則,並且緊密關聯的各組對象也要遵照一些固定規則。然而,過於謹慎的鎖定機制又會致使多個用戶之間毫無心義地互相干擾,從而使系統不可用。
換句話說,咱們如何知道一個由其餘對象組成的對象從哪裏開始,又到何處結束呢?在任何具備持久化數據存儲的系統中,對數據進行修改的事務必需要有範圍,並且要有保持數據一致性的方式(也就是說,保持數據遵照固定規則)。數據庫支持各類鎖機制,並且能夠編寫一些測試來驗證。但這些特殊的解決方案分散了人們對模型的注意力,很快人們就會回到「走一步,看一步」的老路上來。
實際上,要想找到一種兼顧各類問題的解決方案,要求對領域有深入的理解,例如,要了解特定類實例之間的更改頻率這樣的深層次因素。咱們須要找到一個使對象間衝突較少而固定規則聯繫更緊密的模型。
儘管從表面上看這個問題是數據庫事務方面的一個技術難題,但它的根源卻在模型,歸根結底是因爲模型中缺少明肯定義的邊界。從模型獲得的解決方案將使模型更易於理解,而且使設計更易於溝通。當模型被修改時,它將引導咱們對實現作出修改。
首先,咱們須要用一個抽象來封裝模型中的引用。AGGREGATE就是一組相關對象的集合,咱們把它做爲數據修改的單元。每一個AGGREGATE都有一個根(root)和一個邊界(boundary)。邊界定義了AGGREGATE的內部都有什麼。根則是AGGREGATE所包含的一個特定ENTITY。對AGGREGATE而言,外部對象只能夠引用根,而邊界內部的對象之間則能夠互相引用。除根之外的其餘ENTITY都有本地標識,但這些標識只在AGGREGATE內部才須要加以區別,由於外部對象除了根ENTITY以外看不到其餘對象。
汽車修配廠的軟件可能會使用汽車模型。如圖6-2所示。汽車是一個具備全局標識的ENTITY:咱們須要將這部汽車與世界上全部其餘汽車區分開(即便是一些很是類似的汽車)。咱們可使用車輛識別號來進行區分,車輛識別號是爲每輛新汽車分配的惟一標識符。咱們可能想經過4個輪子的位臵跟蹤輪胎的轉動歷史。咱們可能想知道每一個輪胎的里程數和磨損度。要想知道哪一個輪胎在哪兒,必須將輪胎標識爲ENTITY。當脫離這輛車的上下文後,咱們極可能就再也不關心這些輪胎的標識了。若是更換了輪胎並將舊輪胎送到回收廠,那麼軟件將再也不須要跟蹤它們,它們會成爲一堆廢舊輪胎中的一部分。沒有人會關心它們的轉動歷史。更重要的是,即便輪胎被安在汽車上,也不會有人經過系統查詢特定的輪胎,而後看看這個輪胎在哪輛汽車上。人們只會在數據庫中查找汽車,而後臨時查看一下這部汽車的輪胎狀況。所以,汽車是AGGREGATE的根ENTITY,而輪胎處於這個AGGREGATE的邊界以內。另外一方面,發動機組上面都刻有序列號,並且有時是獨立於汽車被跟蹤的。在一些應用程序中,發動機能夠是本身的AGGREGATE的根。
固定規則(invariant)是指在數據變化時必須保持的一致性規則,其涉及AGGREGATE成員之間的內部關係。而任何跨越AGGREGATE的規則將不要求每時每刻都保持最新狀態。經過事件處理、批處理或其餘更新機制,這些依賴會在必定的時間內得以解決。但在每一個事務完成時,AGGREGATE內部所應用的固定規則必須獲得知足,如圖6-3所示。
如今,爲了實現這個概念上的AGGREGATE,須要對全部事務應用一組規則。
根ENTITY具備全局標識,它最終負責檢查固定規則。
根ENTITY具備全局標識。邊界內的ENTITY具備本地標識,這些標識只在AGGREGATE內部纔是惟一的。
AGGREGATE外部的對象不能引用除根ENTITY以外的任何內部對象。根ENTITY能夠把對內部ENTITY的引用傳遞給它們,但這些對象只能臨時使用這些引用,而不能保持引用。根能夠把一個VALUE OBJECT的副本傳遞給另外一個對象,而沒必要關心它發生什麼變化,由於它只是一個VALUE,再也不與AGGREGATE有任何關聯。
做爲上一條規則的推論,只有AGGREGATE的根才能直接經過數據庫查詢獲取。全部其餘對象必須經過遍歷關聯來發現。
AGGREGATE內部的對象能夠保持對其餘AGGREGATE根的引用。
刪除操做必須一次刪除AGGREGATE邊界以內的全部對象。(利用垃圾收集機制,這很容易作到。因爲除根之外的其餘對象都沒有外部引用,所以刪除了根之後,其餘對象均會被回收。)
當提交對AGGREGATE邊界內部的任何對象的修改時,整個AGGREGATE的全部固定規則都必須被知足。
咱們應該將ENTITY和VALUE OBJECT分門別類地彙集到AGGREGATE中,並定義每一個AGGREGATE的邊界。在每一個AGGREGATE中,選擇一個ENTITY做爲根,並經過根來控制對邊界內其餘對象的全部訪問。只容許外部對象保持對根的引用。對內部成員的臨時引用能夠被傳遞出去,但僅在一次操做中有效。因爲根控制訪問,所以不能繞過它來修改內部對象。這種設計有利於確保AGGREGATE中的對象知足全部固定規則,也能夠確保在任何狀態變化時AGGREGATE做爲一個總體知足固定規則。
有一個可以聲明AGGREGATE的技術框架是頗有幫助的,這樣就能夠自動實施鎖機制和其餘一些功能。若是沒有這樣的技術框架,團隊就必須靠自我約束來使用事先商定的AGGREGATE,並按照這些AGGREGATE來編寫代碼。
示例 採購訂單的完整性
一個典型的採購訂單(Purchase Order,PO)視圖,它被分解爲採購項(Line Item),一條固定規則是採購項的總量不能超過PO總額的限制。當前實現存在如下3個互相關聯的問題。
(1) 固定規則的實施。當添加新採購項時,PO檢查總額,若是新增的採購項使總額超出限制,則將PO標記爲無效。正如咱們將要看到的那樣,這種保護機制並不充分。
(2) 變動管理。當PO被刪除或存檔時,各個採購項也將被一塊處理,但模型並無給出關係應該在何處中止。在不一樣時間更改部件(Part)價格所產生的影響也不明確。
(3) 數據庫共享。數據庫會出現因爲多個用戶競爭使用而帶來的問題。
多個用戶將併發地輸入和更新各個PO,所以必須防止他們互相干擾。讓咱們從一個很是簡單的策略開始,當一個用戶開始編輯任何一個對象時,鎖定該對象,直到用戶提交事務。這樣,當George編輯採購項001時,Amanda就沒法訪問該項。Amanda能夠編輯其餘PO上的任何採購項(包括George正在編輯的PO上的其餘採購項)
每一個用戶都將從數據庫讀取對象,並在本身的內存空間中實例化對象,然後在那裏查看和編輯對象。只有當開始編輯時,纔會請求進行數據庫鎖定。所以,George和Amanda能夠同時工做,只要他們不一樣時編輯相同的採購項便可。一切正常,直到George和Amanda開始編輯同一個PO上的不一樣採購項.
從這兩個用戶和他們各自軟件的角度來看,他們的操做都沒有問題,由於他們忽略了事務期間數據庫其餘部分所發生的變化,並且每一個用戶都沒有修改被對方鎖定的採購項。當這兩個用戶保存了修改以後,數據庫中就存儲了一個違反領域模型固定規則的PO。一條重要的業務規則被破壞了,但並無人知道
顯然,鎖定單個行並非一種充分的保護機制。若是一次鎖定一個PO,能夠防止這樣的問題發生
直到Amanda解決這個問題以前,程序將不容許保存這個事務,Amanda能夠經過提升限額或減小一把吉他來解決此問題。這種機制防止了問題,若是大部分工做分佈在多個PO上,那麼這多是個不錯的解決方案。但若是是不少人同時對一個大PO的不一樣項進行操做時,這種鎖定機制就顯得很笨拙了。
即使是不少小PO,也存在其餘方法破壞這條固定規則。讓咱們看看「Part」。若是在Amanda將長號加入訂單時,有人更改了長號的價格,這不也會破壞固定規則嗎?
咱們試着除了鎖定整個PO以外,也鎖定Part,當George、Amanda和Sam在不一樣PO上工做時將會發生的狀況。
工做變得愈來愈麻煩,由於在Part上出現了不少爭用的狀況。這樣就會發生圖6-10中的結果:3我的都須要等待。
如今咱們能夠開始改進模型,在模型中加入如下業務知識。
(1) Part在不少PO中使用(會產生高競爭)。
(2) 對Part的修改少於對PO的修改。
(3) 對Price(價格)的修改不必定要傳播到現有PO,它取決於修改價格時PO處於什麼狀態。
當考慮已經交貨並存檔的PO時,第三點尤其明顯。它們顯示的固然是填寫時的價格,而不是當前價格。
這個模型獲得的實現能夠確保知足PO和採購項相關的固定規則,同時,修改部件的價格將不會當即影響引用部件的採購項。涉及面更廣的規則能夠經過其餘方式來知足。例如,系統能夠天天爲用戶列出價格過時的採購項,這樣用戶就能夠決定是更新仍是去掉採購項。但這並非必須一直保持的固定規則。經過減小採購項對Part的依賴,能夠避免爭用,而且可以更好地反映出業務的現實狀況。同時,增強PO與採購項之間的關係能夠確保遵照這條重要的業務規則。
AGGREGATE強制了PO與採購項之間符合業務實際的所屬關係。PO和採購項的建立及刪除很天然地被聯繫在一塊兒,而Part的建立和刪除倒是獨立的。
AGGREGATE劃分出一個範圍,在這個範圍內,生命週期的每一個階段都必須知足一些固定規則。接下來要討論的兩種模式FACTORY和REPOSITORY都是在AGGREGATE上執行操做,它們將特定生命週期轉換的複雜性封裝起來……
我的理解:徹底沒看懂,好像是建模處理資源競爭的問題。
當建立一個對象或建立整個AGGREGATE時,若是建立工做很複雜,或者暴露了過多的內部結構,則可使用FACTORY進行封裝。
對象的功能主要體如今其複雜的內部配臵以及關聯方面。咱們應該一直對對象進行提煉,直到全部與其意義或在交互中的角色無關的內容被徹底剔除爲止。一個對象在它的生命週期中要承擔大量職責。若是再讓複雜對象負責自身的建立,那麼職責過載將會致使問題。
汽車發動機是一種複雜的機械裝臵,它由數十個零件共同協做來履行發動機的職責——使軸轉動。咱們能夠試着設計一種發動機組,讓它本身抓取一組活塞並塞到汽缸中,火花塞也能夠本身找到插孔並把本身擰進去。但這樣組裝的複雜機器可能沒有咱們常見的發動機那樣可靠或高效。相反,咱們用其餘東西來裝配發動機。或許是機械師,或者是工業機器人。不管是機器人仍是人,實際上都比兩者要裝配的發動機複雜。裝配零件的工做與使軸旋轉的工做徹底無關。只是在生產汽車時才須要裝配工,咱們駕駛時並不須要機器人或機械師。因爲汽車的裝配和駕駛永遠不會同時發生,所以將這兩種功能合併到同一個機制中是毫無價值的。同理,裝配複雜的複合對象的工做也最好與對象要執行的工做分開。
正如對象的接口應該封裝對象的實現同樣(從而使客戶無需知道對象的工做機理就可使用對象的功能),FACTORY封裝了建立複雜對象或AGGREGATE所需的知識。它提供了反映客戶目標的接口,以及被建立對象的抽象視圖。
應該將建立複雜對象的實例和AGGREGATE的職責轉移給單獨的對象,這個對象自己可能沒有承擔領域模型中的職責,但它還是領域設計的一部分。提供一個封裝全部複雜裝配操做的接口,並且這個接口不須要客戶引用要被實例化的對象的具體類。在建立AGGREGATE時要把它做爲一個總體,並確保它知足固定規則。
FACTORY有不少種設計方式。[Gamma et al.1995]中詳盡論述了幾種特定目的的建立模式,包括FACTORY METHOD(工廠方法)、ABSTRACT FACTORY(抽象工廠)和BUILDER(構建器)。該書主要研究了適用於最複雜的對象構造問題的模式。本書的重點並非深刻討論FACTORY的設計問題,而是要代表FACTORY的重要地位——它是領域設計的重要組件。正確使用FACTORY有助於保證MODEL-DRIVEN DESIGN沿正確的軌道前進。
任何好的工廠都需知足如下兩個基本需求
(1) 每一個建立方法都是原子的,並且要保證被建立對象或AGGREGATE的全部固定規則。FACTORY生成的對象要處於一致的狀態。在生成ENTITY時,這意味着建立知足全部固定規則的整個AGGREGATE,但在建立完成後能夠向聚合添加可選元素。在建立不變的VALUE OBJECT時,這意味着全部屬性必須被初始化爲正確的最終狀態。若是FACTORY經過其接口收到了一個建立對象的請求,而它又沒法正確地建立出這個對象,那麼它應該拋出一個異常,或者採用其餘機制,以確保不會返回錯誤的值。
(2) FACTORY應該被抽象爲所需的類型,而不是所要建立的具體類。[Gamma et al.1995]中的高級FACTORY模式介紹了這一話題
我的理解:這個我懂了,對象的建立若是很是複雜(要組裝或者初始化不少參數,規則必定)就可使用工廠模式,技術開發人員應該很是瞭解工廠模式,業務不須要知道啥是工廠模式。
總結:沒看懂,這部分更加註重程序對象和數據庫的設計,還有就是模型的生命週期,好好了解下設計模式和數據庫設計範式應該就夠了。