第一部分 運(yùn)用領(lǐng)域模型
- 在領(lǐng)域驅(qū)動(dòng)的設(shè)計(jì)中冷守,3個(gè)基本用途決定了模型的選擇:
- 模型和設(shè)計(jì)的核心互相影響样刷。正是模型與實(shí)現(xiàn)之間的緊密聯(lián)系才使模型變得有用嫁审,并確保我們?cè)谀P椭兴M(jìn)行的分析能夠轉(zhuǎn)化為最終產(chǎn)品(即一個(gè)可運(yùn)行的程序)
- 模型是團(tuán)隊(duì)所有成員使用的通用語(yǔ)言的中樞荐吵。由于模型與實(shí)現(xiàn)之間的關(guān)聯(lián)寄雀,開(kāi)發(fā)人員可以使用該語(yǔ)言來(lái)討論程序
- 模型是濃縮的知識(shí)杭隙。模型是團(tuán)隊(duì)一致認(rèn)同的領(lǐng)域知識(shí)的組織方式和重要元素的區(qū)分方式诬乞。透過(guò)我們?nèi)绾芜x擇術(shù)語(yǔ)诡曙、分解概念以及將概念聯(lián)系起來(lái)埋哟,模型記錄了我們看待領(lǐng)域的方式笆豁。
- 軟件的核心是其為用戶解決領(lǐng)域相關(guān)的問(wèn)題的能力
第1章 消化知識(shí)
- 模型用來(lái)描述人們所關(guān)注的現(xiàn)實(shí)和想法某方面。
- 用戶軟件的問(wèn)題區(qū)域就是軟件的領(lǐng)域
- 模型的作用:模型和設(shè)計(jì)的核心互相影響;模型是團(tuán)隊(duì)成員使用的語(yǔ)言中樞闯狱;模型是濃縮的知識(shí)
1.1 有效建模的要素
- 以下幾方面因素促使上述案例得以成功
- 模型和實(shí)現(xiàn)的綁定
- 建立一種基于模型的語(yǔ)言
- 開(kāi)發(fā)了一種蘊(yùn)含豐富知識(shí)的模型
- 提煉模型
- 頭腦風(fēng)暴和實(shí)驗(yàn)
1.2知識(shí)消化
- 知識(shí)消化并非一項(xiàng)孤立的活動(dòng)煞赢,它一般是在開(kāi)發(fā)人員的領(lǐng)導(dǎo)下,由開(kāi)發(fā)人員與領(lǐng)域?qū)<医M成的團(tuán)隊(duì)來(lái)共同協(xié)作哄孤。他們共同收集信息照筑,并通過(guò)消化而將它組織為有用的形式
- 信息的原始資料來(lái)自于領(lǐng)域?qū)<翌^腦中的知識(shí)、現(xiàn)有系統(tǒng)的用戶瘦陈、以及技術(shù)團(tuán)隊(duì)在現(xiàn)有遺留系統(tǒng)或者同領(lǐng)域其他項(xiàng)目中積累的經(jīng)驗(yàn)
1.3 持續(xù)學(xué)習(xí)
- 高效率的團(tuán)隊(duì)需要有意識(shí)的積累知識(shí)凝危,并持續(xù)學(xué)習(xí).對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),這意味著既要完善技術(shù)知識(shí)双饥,也要培養(yǎng)一般的領(lǐng)域建模技巧(如本書(shū)中所講的那些技巧)媒抠。但這也包括認(rèn)真學(xué)習(xí)他們正在從事的特定領(lǐng)域的知識(shí)
1.4 知識(shí)豐富的設(shè)計(jì)
- 通過(guò)像PCB示例這樣的模型獲得到的知識(shí)遠(yuǎn)遠(yuǎn)不只是“發(fā)現(xiàn)名詞”,業(yè)務(wù)活動(dòng)和規(guī)則如何涉及到的實(shí)體一樣咏花,都是領(lǐng)域的核心趴生,任何領(lǐng)域都有各種類別的概念
- 當(dāng)我們的建模不再局限于尋找實(shí)體和值對(duì)象時(shí),我們才能充分吸收知識(shí)昏翰,因?yàn)闃I(yè)務(wù)規(guī)則之間可能存在不一致苍匆。正是通過(guò)和軟件專家緊密協(xié)作來(lái)消化知識(shí)的過(guò)程才使得規(guī)則得以澄清和充實(shí),并消除規(guī)則之間的矛盾以及刪除無(wú)用的規(guī)則
1.5 深層次模型
- 知識(shí)消化是一種探索棚菊,永無(wú)止境
第2章 交流與語(yǔ)言的使用
- 領(lǐng)域模型可成為軟件項(xiàng)目通用語(yǔ)言的核心浸踩。該模型是一組得自于項(xiàng)目人員頭腦中的概念,以及反映了領(lǐng)域深層含義的術(shù)語(yǔ)和關(guān)系统求。這些術(shù)語(yǔ)和相互關(guān)系提供了模型語(yǔ)言的語(yǔ)義检碗,雖然語(yǔ)言是為領(lǐng)域量身定制的,但就技術(shù)開(kāi)發(fā)而言码邻,其依然足夠精確折剃。正是這條至關(guān)重要的紐帶,將模型與開(kāi)發(fā)活動(dòng)結(jié)合在一起像屋,并使模型與代碼緊密綁定怕犁。
2.1 模式:UBIQUITOUS LANGUAGE
- 要想創(chuàng)建一種靈活、蘊(yùn)含豐富知識(shí)的設(shè)計(jì)己莺,需要一種通用的奏甫、共享的團(tuán)隊(duì)語(yǔ)言,以及對(duì)語(yǔ)言的不斷試驗(yàn)凌受。
- 如果語(yǔ)言支離破碎的阵子,項(xiàng)目必將遭遇嚴(yán)重問(wèn)題。領(lǐng)域?qū)<沂褂盟麄冏约旱男g(shù)語(yǔ)胜蛉,而技術(shù)團(tuán)隊(duì)所使用的的語(yǔ)言經(jīng)過(guò)調(diào)整款筑,以便于涉及角度討論領(lǐng)域智蝠。
- 通用語(yǔ)言詞匯主要包括類和操作名稱
- 將模型作為語(yǔ)言的支柱腾么。確保團(tuán)隊(duì)在內(nèi)部的所有交流中以及代碼中堅(jiān)持使用這種語(yǔ)言奈梳。在畫(huà)圖、寫(xiě)東西解虱,特別是講話時(shí)也要使用這種語(yǔ)言攘须。
2.2 “大聲的”建模
- 改善模型的最佳方式之一就是通過(guò)對(duì)話進(jìn)行研究,試著大聲的說(shuō)出可能的模型變化過(guò)程中各種結(jié)構(gòu)
- 討論系統(tǒng)時(shí)要結(jié)合模型殴泰,使用模型元素及其交互來(lái)大聲的說(shuō)出來(lái)于宙。并且按照模型允許的方式將各種概念結(jié)合在一起找到更簡(jiǎn)單的方式說(shuō)出你要講的話。并且將新的想法應(yīng)用到圖和代碼中悍汛。
2.3 一個(gè)團(tuán)隊(duì)捞魁,一種語(yǔ)言
-
如果連經(jīng)驗(yàn)豐富的領(lǐng)域模型專家都不能理解模型,那么模型一定出了問(wèn)題
2.4文檔和圖
- 簡(jiǎn)單离咐、非正式的UML圖能夠維系整個(gè)討論
- 通常的用法是以圖為主谱俭,輔以文本注釋;而我更愿意以文本為主宵蛀,用精心挑選的簡(jiǎn)化圖作為說(shuō)明
- 使用uml昆著、對(duì)象交互圖描述模型
- 設(shè)計(jì)的細(xì)節(jié)應(yīng)該體現(xiàn)在代碼中
- 模型不是圖
2.4.1 書(shū)面設(shè)計(jì)文檔
- 文檔應(yīng)該作為口頭交流和代碼的補(bǔ)充
- 文檔應(yīng)該鮮活并且保持最新
- 設(shè)計(jì)文檔的最大價(jià)值在于解釋模型的概念,幫助在代碼的細(xì)節(jié)中指引方向术陶,或許還可以幫助人們深入了解模型預(yù)期的使用風(fēng)格
- 檔必須深入到各種項(xiàng)目活動(dòng)中去凑懂。判斷是否做到這一點(diǎn)的最簡(jiǎn)單方法,是觀察文檔與UBIQUITOUS LANGUAGE之間的交互
2.4.2 完全依賴可執(zhí)行代碼的情況
2.5 解釋性模型
- 解釋性模型提供了一定的自由度梧宫,可以專門為某一個(gè)特殊主體定制一些表達(dá)能力更加豐富的風(fēng)格
-
解釋性模型不必是對(duì)象模型接谨,而且最好不是,避免人們錯(cuò)誤的認(rèn)為這些模型和軟件設(shè)計(jì)是一致的
第3章 綁定模型和實(shí)現(xiàn)
3.1模式:model-driven design
- 如果整個(gè)程序設(shè)計(jì)或者其核心部分沒(méi)有與領(lǐng)域模型相對(duì)應(yīng)塘匣,那么這個(gè)模型就是沒(méi)有價(jià)值的脓豪,軟件的正確性也值得懷疑。同時(shí)馆铁,模塊和設(shè)計(jì)功能之間過(guò)于復(fù)雜的對(duì)應(yīng)關(guān)系也是難于理解的跑揉,在實(shí)際項(xiàng)目中,當(dāng)設(shè)計(jì)改變時(shí)也無(wú)法維護(hù)這種關(guān)系埠巨。若分析與設(shè)計(jì)之間存在嚴(yán)重分歧历谍,那么在分析和設(shè)計(jì)活動(dòng)中所獲得的知識(shí)無(wú)法彼此分享。
- 軟件系統(tǒng)各個(gè)部分的設(shè)計(jì)應(yīng)該忠實(shí)的反應(yīng)領(lǐng)域模型辣垒,以便體現(xiàn)這兩者之間的明確對(duì)應(yīng)關(guān)系望侈。我們應(yīng)該反復(fù)檢查并修改模型,以便軟件可以更加自然的實(shí)現(xiàn)模型勋桶,及時(shí)想讓模型反應(yīng)出更深層次的領(lǐng)域概念時(shí)也該如此脱衙。我們需要的模型不但應(yīng)該滿足這兩種需求侥猬,還應(yīng)該能夠支持健壯的ubiquitous language (通用語(yǔ)言)
3.2 建模方式和工具支持
- 面向?qū)ο笤O(shè)計(jì)目前大多數(shù)項(xiàng)目所使用的建模模式,也是本書(shū)中使用的主要方法
3.3 揭示主旨:為什么模型對(duì)用戶至關(guān)重要
- 分析捐韩、設(shè)計(jì)模型 vs 用戶模型
3.4 模式:hands-on modeler
- 如果開(kāi)發(fā)人員發(fā)現(xiàn)不需要對(duì)模型負(fù)責(zé)退唠,或許不知道模型如何為應(yīng)用服務(wù),那么這個(gè)模型和應(yīng)用沒(méi)有任何關(guān)聯(lián)荤胁。如果開(kāi)發(fā)人員沒(méi)有意識(shí)到修改代碼就是修改模型瞧预,那么他們對(duì)程序的重構(gòu)不但不會(huì)增強(qiáng)模型的作用,反而會(huì)削弱它的效果仅政。
- model driven design兩個(gè)要素:模型要支持有效的實(shí)現(xiàn)和抽象出關(guān)鍵的領(lǐng)域知識(shí)
- 任何參與建模的技術(shù)人員垢油,不管在項(xiàng)目中的主要職責(zé)是什么,都必須花時(shí)間了解代碼圆丹。任何負(fù)責(zé)修改代碼的人員必須學(xué)會(huì)用代碼來(lái)表達(dá)模型滩愁。每一個(gè)開(kāi)發(fā)人員都必須不同程度地參與模型討論并且與領(lǐng)域?qū)<冶3致?lián)系。參與不同工作的人都必須有意識(shí)地通過(guò)UBIQUITOUS LANGUAGE與接觸代碼的人及時(shí)交換關(guān)于模型的想法辫封。
第二部分 模型驅(qū)動(dòng)設(shè)計(jì)的構(gòu)造塊
第4章 分離領(lǐng)域
- 注意模型和對(duì)象的生成順序
-
職責(zé)驅(qū)動(dòng)設(shè)計(jì)硝枉、契約式設(shè)計(jì)
4.1 模式:layer architecture
-
分層:用戶界面層、應(yīng)用層秸讹、領(lǐng)域?qū)犹戳⒒A(chǔ)設(shè)施層
給復(fù)雜的應(yīng)用程序劃分層次。在每一層內(nèi)分別進(jìn)行設(shè)計(jì)璃诀,使其具有內(nèi)聚性并且只依賴于它的下層弧可。采用標(biāo)準(zhǔn)的架構(gòu)模式,只與上層進(jìn)行松散的耦合劣欢。將所有與領(lǐng)域模型相關(guān)的代碼放在一個(gè)層中棕诵,并把它與用戶界面層、應(yīng)用層以及基礎(chǔ)設(shè)施層的代碼分開(kāi)凿将。領(lǐng)域?qū)ο髴?yīng)該將重點(diǎn)放在如何表達(dá)領(lǐng)域模型上校套,而不需要考慮自己的顯示和存儲(chǔ)問(wèn)題,也無(wú)需管理應(yīng)用任務(wù)等內(nèi)容牧抵。這使得模型的含義足夠豐富笛匙,結(jié)構(gòu)足夠清晰,可以捕捉到基本的業(yè)務(wù)知識(shí)犀变,并有效地使用這些知識(shí)
關(guān)注點(diǎn)分離妹孙,但是也要保證各個(gè)層次的交互
layered architecture 的基本原則是層中的任何元素都僅僅依賴于本層的其它元素或者其下層的元素。向上通信必須通過(guò)間接的方式進(jìn)行
4.1.1 將各層關(guān)聯(lián)起來(lái)
- 各層之間是松散鏈接的获枝,層與層的依賴關(guān)系只能是單向的蠢正。
- 如果下層元素需要與上層元素進(jìn)行通信,則需要采用回調(diào)模式或者observers模式
- 應(yīng)用層和領(lǐng)域?qū)涌梢哉{(diào)用基礎(chǔ)設(shè)施層所提供的service省店。然而嚣崭,并不是所有的基礎(chǔ)設(shè)施都可以供上層調(diào)用的service形式出現(xiàn)(如為所有領(lǐng)域?qū)ο筇峁┏橄蠡?
4.1.2 架構(gòu)框架
- 早期的j2ee應(yīng)用程序通常會(huì)將所有領(lǐng)域?qū)ο髮?shí)現(xiàn)為“實(shí)體對(duì)象”笨触,這種實(shí)現(xiàn)不僅影響程序性能,而且會(huì)減慢開(kāi)發(fā)速度雹舀。取而代之的最佳實(shí)踐是利用j2ee框架實(shí)現(xiàn)大粒度對(duì)象芦劣,而用普通的java對(duì)象實(shí)現(xiàn)大部分的業(yè)務(wù)邏輯
4.2 領(lǐng)域?qū)邮悄P偷木?/h2>
- 領(lǐng)域?qū)觿t是領(lǐng)域模型以及所有與其直接相關(guān)的設(shè)計(jì)元素的表現(xiàn),它由業(yè)務(wù)邏輯的設(shè)計(jì)和實(shí)現(xiàn)組成
4.3 模式:the smart ui“反模式”
- smart ui 是另一種設(shè)計(jì)方法,與領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方法迥然不同且互不兼容葱跋。是一種簡(jiǎn)單快速實(shí)現(xiàn)業(yè)務(wù)的一種方式持寄。
- 如果一個(gè)經(jīng)驗(yàn)并不豐富的項(xiàng)目團(tuán)隊(duì)要完成一個(gè)簡(jiǎn)單的項(xiàng)目,卻決定使用MODEL-DRIVEN DESIGN以及LAYERED ARCHITECTURE娱俺,那么這個(gè)項(xiàng)目組將會(huì)經(jīng)歷一個(gè)艱難的學(xué)習(xí)過(guò)程。團(tuán)隊(duì)成員不得不去掌握復(fù)雜的新技術(shù)废麻,艱難地學(xué)習(xí)對(duì)象建模
-
smart ui 與DDD對(duì)比
4.4 其他分離模式
第5章 軟件中所表示的模型
- 一個(gè)對(duì)象是用來(lái)表示某種具有連續(xù)性和標(biāo)識(shí)的事務(wù)呢荠卷?還是用來(lái)描述某種狀態(tài)的屬性呢?這是entity和value object之間的根本區(qū)別
- 領(lǐng)域中還有一些方面適合用動(dòng)作或者操作來(lái)表示烛愧,這比用對(duì)象來(lái)表示更加清楚油宜。這些方面最好用service來(lái)表示,而不應(yīng)該把操作的責(zé)任強(qiáng)加到entity或者value object 上
- 每個(gè)設(shè)計(jì)決策都應(yīng)該是在深入理解領(lǐng)域中的某些知識(shí)做出的
5.1 關(guān)聯(lián)
- 對(duì)象之間的關(guān)聯(lián)使得模型和實(shí)現(xiàn)之間的交互變得更復(fù)雜
- 模型中的每個(gè)可遍歷的關(guān)聯(lián)怜姿,軟件中都要有同樣的屬性機(jī)制
- 例如一對(duì)多關(guān)聯(lián)可以用一個(gè)集合類型的實(shí)例變量來(lái)實(shí)現(xiàn)慎冤,但設(shè)計(jì)無(wú)需如此,可能沒(méi)有集合沧卢,這時(shí)可以用一個(gè)訪問(wèn)方法來(lái)查詢數(shù)據(jù)庫(kù)蚁堤,找到相關(guān)記錄,并用這些記錄初始化對(duì)象但狭。這兩種設(shè)計(jì)反應(yīng)了同一個(gè)模型披诗。
- 限定多對(duì)多的的關(guān)聯(lián)方向 可以有效的將其簡(jiǎn)化為一對(duì)多的設(shè)計(jì),從而實(shí)現(xiàn)一種簡(jiǎn)單的多的設(shè)計(jì)
- 堅(jiān)持將關(guān)聯(lián)限定為領(lǐng)域所傾向的方向立磁,不僅可以提高這些關(guān)聯(lián)的表達(dá)力并簡(jiǎn)化其實(shí)現(xiàn)呈队,而且還可以突出剩下的雙向關(guān)聯(lián)的重要性。
- 當(dāng)雙向關(guān)聯(lián)是領(lǐng)域的一個(gè)語(yǔ)義特征時(shí)唱歧,或者應(yīng)用程序的功能要求雙向關(guān)聯(lián)時(shí)宪摧,就需要保留它,以便于表達(dá)出這些需求颅崩。
- 最終的簡(jiǎn)化是清除那些對(duì)當(dāng)前工作或者模型對(duì)象的基本含義來(lái)說(shuō)不重要的關(guān)聯(lián)几于。
5.2 模式:Entity,又名peference object
- 很多對(duì)象不是通過(guò)他們的屬性定義的挨摸,而是通過(guò)連續(xù)性和標(biāo)識(shí)定義的孩革。
- 實(shí)體的基本概念是一種貫穿整個(gè)生命周期的抽象的連續(xù)性。
- 主要由標(biāo)識(shí)定義的對(duì)象被稱作entity得运。entity 具有生命周期膝蜈。這期間他們的形式和內(nèi)容可能發(fā)生根本性的改變锅移,但必須保持一種內(nèi)在的連續(xù)性。
- entity 的判斷條件:在整個(gè)生命周期是連續(xù)性的饱搏;它的區(qū)別并不是由那些對(duì)客戶特別重要的屬性決定的
- 在一個(gè)模型中非剃,并不是所有的對(duì)象都是有意義的entity。標(biāo)識(shí)是entity 一個(gè)微妙有意義的屬性推沸,不能交給語(yǔ)言的自動(dòng)特性處理备绽。
- 當(dāng)一個(gè)對(duì)象由其標(biāo)識(shí)(而不是屬性)區(qū)分時(shí),那么在模型中應(yīng)該主要通過(guò)標(biāo)識(shí)來(lái)確定該對(duì)象的定義鬓催。使類定義變得簡(jiǎn)單肺素,并集中關(guān)注生命周期的連續(xù)性和標(biāo)識(shí)。定義一種區(qū)分每個(gè)對(duì)象的方式宇驾,這
種方式應(yīng)該與其形式和歷史無(wú)關(guān)倍靡。要格外注意那些需要通過(guò)屬性來(lái)匹配對(duì)象的需求。在定義標(biāo)識(shí)操作時(shí)课舍,要確保這種操作為每個(gè)對(duì)象生成唯一的結(jié)果塌西,這可以通過(guò)附加一個(gè)保證唯一性的符號(hào)來(lái)實(shí)現(xiàn)。這種定義標(biāo)識(shí)的方法可能來(lái)自外部筝尾,也可能是由系統(tǒng)創(chuàng)建的任意標(biāo)識(shí)符捡需,但它在模型中必須是唯一的標(biāo)識(shí)。模型必須定義出“符合什么條件才算是相同的事物”
5.2.1 entity 建模
- Entity 的基本職責(zé)是保證連續(xù)性筹淫,以便其行為是可預(yù)測(cè)和和更清楚站辉。
- 抓住entity 對(duì)象的基本特征或者屬性,尤其是用于識(shí)別贸街,查找庵寞,匹配的特征。應(yīng)該將特性和行為轉(zhuǎn)移到與核心實(shí)體相關(guān)聯(lián)的對(duì)象上
5.2.2 設(shè)計(jì)標(biāo)識(shí)操作
- 每個(gè)實(shí)體都必須有一種建立標(biāo)識(shí)的操作薛匪,以便與其他對(duì)象區(qū)分開(kāi)
- 某些數(shù)據(jù)屬性或者屬性組合可以確保他們?cè)谙到y(tǒng)中具有唯一性捐川,或者在這些屬性加一些簡(jiǎn)單約束可以使其具有唯一性
- 當(dāng)對(duì)象屬性沒(méi)辦法形成唯一鍵時(shí),經(jīng)常用到的解決方案是為每個(gè)實(shí)體附加一個(gè)在類中的唯一的符號(hào)
5.3 模式:value object
- 很多對(duì)象是沒(méi)有概念上的標(biāo)識(shí)逸尖,它們描述了一個(gè)事務(wù)的某種特征
- 用于描述領(lǐng)域的某個(gè)方面而沒(méi)有概念上的標(biāo)識(shí)稱為value object古沥。對(duì)于這些元素,我們只關(guān)心他們是什么娇跟,而不關(guān)心他們是誰(shuí)岩齿。
- value object 可以是其他對(duì)象的集合。
- Value object 可以引用entity苞俘。
- Value object 經(jīng)常作為參數(shù)在對(duì)象之間傳遞盹沈。
- 當(dāng)我們只關(guān)心一個(gè)模型元素的屬性時(shí),應(yīng)該把它歸類為value object吃谣。我們應(yīng)該使用這個(gè)模型元素能夠標(biāo)識(shí)出其屬性的意義乞封,并為它提供相關(guān)的功能做裙。value object 應(yīng)該是不可變的。不要為它分配任何標(biāo)識(shí)肃晚,而且不要把它設(shè)計(jì)成entity那么復(fù)雜锚贱。
5.3.1 設(shè)計(jì)value object
- 在設(shè)計(jì)值對(duì)象有多種選擇,包括復(fù)制关串,共享或者保證值對(duì)象不變
- value object為性能優(yōu)化提供了更多的選擇
- 如果屬性值發(fā)生改變拧廊,我們應(yīng)該使用一個(gè)不同的value object,而不是修改現(xiàn)有的object晋修。但是有些情況出于性能考慮吧碾,仍然需要讓value object是可變額。
- 以下幾種情況最好使用共享飞蚓,這樣可以發(fā)揮共享的最大價(jià)值并最大限度地減少麻煩:
- 節(jié)省數(shù)據(jù)庫(kù)空間或減少對(duì)象數(shù)量是一個(gè)關(guān)鍵要求時(shí)滤港;
- 通信開(kāi)銷很低時(shí)(如在中央服務(wù)器中);
- 共享的對(duì)象被嚴(yán)格限定為不可變時(shí)
- 在有些情況下出于性能考慮趴拧,仍需要讓VALUEOBJECT是可變的。這包括以下因素:
- 如果VALUE頻繁改變山叮;
- 如果創(chuàng)建或刪除對(duì)象的開(kāi)銷很大著榴;
- 如果替換(而不是修改)將打亂集群(像前面示例中討論的那樣);
- 如果VALUE的共享不多屁倔,或者共享不會(huì)提高集群性能脑又,或其他某種技術(shù)原因
5.3.2 設(shè)計(jì)包含value object 的關(guān)聯(lián)
- 我們應(yīng)該避免value object的雙向關(guān)聯(lián),如果存在锐借,請(qǐng)檢查是否合理
5.4 模式:Service
- 有些操作是無(wú)法放到entity 和value object 上的问麸。這些操作從概念上講不屬于任何對(duì)象。與其把他們強(qiáng)制歸于哪一類钞翔,不如順其自然的在模型中引入一種新的元素严卖,那就是Service。
- 一種比較常見(jiàn)的錯(cuò)誤行為是沒(méi)有努力為這類行為找到合適的對(duì)象布轿,而是轉(zhuǎn)化為面向過(guò)程編程
- 一些領(lǐng)域概念不適合被建模為對(duì)象哮笆。如果勉強(qiáng)把這些重要的領(lǐng)域功能歸為entity和value object的職責(zé),那么不是歪曲了基于模型的對(duì)象的定義汰扭,就是人為的增加了一些無(wú)意義的對(duì)象稠肘。
- Service 是作為接口提供一種操作,它在模型中是獨(dú)立的萝毛,不像entity 封裝內(nèi)部狀態(tài)项阴。可以在領(lǐng)域?qū)邮褂谩?/li>
- 所謂service笆包,強(qiáng)調(diào)的是與其他對(duì)象的關(guān)系环揽。與entity略荡、value object不同,它只是定義了能夠?yàn)榭蛻糇鍪裁词硌荨ervice往往是以一個(gè)活動(dòng)來(lái)命名撞芍,而不是一個(gè)entity來(lái)命名,也就是說(shuō)跨扮,它是一個(gè)動(dòng)詞而不是名詞序无。 參數(shù)和結(jié)果應(yīng)該是領(lǐng)域?qū)ο?/li>
- 好的service 有三個(gè)特征:
- 與領(lǐng)域概念相關(guān)的操作不是entity 或者value 的一個(gè)自然組成部分
- 接口是根據(jù)領(lǐng)域模型的其他元素定義的
- 操作是無(wú)狀態(tài)的
- 當(dāng)領(lǐng)域的某個(gè)重要過(guò)程或者操作不是entity 或者value object的自然職責(zé)時(shí),應(yīng)該在模型中添加這個(gè)獨(dú)立接口操作衡创,并將其聲明為service.定義接口時(shí)要使用模型語(yǔ)言帝嗡,并確保操作名稱是ubiquitous language的術(shù)語(yǔ)。此外璃氢,應(yīng)該使service稱為無(wú)狀態(tài)
5.4.1 service 與孤立的領(lǐng)域?qū)?/h3>
-
在大多數(shù)開(kāi)發(fā)系統(tǒng)中哟玷,在一個(gè)領(lǐng)域?qū)ο蠛屯獠抠Y源之間直接建立一個(gè)接口是很別扭的。我們可以利用一個(gè)facade將這樣的service包裝起來(lái)一也,這樣外觀可能以模型作為輸入术吗,并返回一個(gè)“Fund Transfer”對(duì)象。
5.4.2 粒度
- service可以控制領(lǐng)域?qū)又械慕涌诘牧6润锱剩⑶冶苊饪蛻舳伺centity和value object耦合子漩。
- 由于應(yīng)用層負(fù)責(zé)對(duì)領(lǐng)域?qū)ο蟮男袨檫M(jìn)行協(xié)調(diào),因此細(xì)粒度的領(lǐng)域?qū)ο罂赡軙?huì)把領(lǐng)域?qū)拥闹R(shí)蔓延到應(yīng)用層或者用戶界面代碼當(dāng)中舆蝴。
- 明智地引入領(lǐng)域?qū)臃?wù)有助于在應(yīng)用層和領(lǐng)域?qū)又g保持一條明確的界限
5.4.3 對(duì)Service 的訪問(wèn)
5.5 模式:module谦絮,也稱為package
-
module為人們提供兩種觀察模型的方式,一是可以在module中查詢細(xì)節(jié),而不會(huì)被整個(gè)模型淹沒(méi)洁仗,二是觀察module之間的關(guān)系层皱,而考慮其內(nèi)部細(xì)節(jié)。
- module的名稱應(yīng)該是ubiquitous language中的術(shù)語(yǔ)赠潦。module及其名稱應(yīng)該反映出領(lǐng)域的深層知識(shí)叫胖。
- 如果一個(gè)類依賴另一個(gè)包中的類,但是本地module對(duì)于該module并沒(méi)有概念上的依賴關(guān)系祭椰,那么或許應(yīng)該移動(dòng)一個(gè)類臭家,或者考慮重新組織module
5.5.1 敏捷的module
- MODULE需要與模型的其他部分一同演變。這意味著MODULE的重構(gòu)必須與模型和代碼一起進(jìn)行方淤。但這種重構(gòu)通常不會(huì)發(fā)生钉赁。更改MODULE可能需要大范圍地更新代碼。這些更改可能會(huì)對(duì)團(tuán)隊(duì)溝通起到破壞作用携茂,甚至?xí)恋K開(kāi)發(fā)工具(如源代碼控制系統(tǒng))的使用你踩。因此,MODULE結(jié)構(gòu)和名稱往往反映了模型的較早形式,而類則不是這樣
5.5.2 通過(guò)基礎(chǔ)設(shè)施打包時(shí)存在的隱患
- 除非真正的有必要將代碼分布到不同的機(jī)器上带膜,否則就把實(shí)現(xiàn)單一概念對(duì)象的所有代碼放在同一模塊中
- 利用打包把領(lǐng)域?qū)訌钠渌a中分離出來(lái)吩谦,否則,就盡可能讓領(lǐng)域開(kāi)發(fā)人員自由決定對(duì)象的打包方式膝藕,以便于支持他們的模型和設(shè)計(jì)選擇
5.6 建模范式
5.6.1 對(duì)象方式流行的原因
5.6.2對(duì)象世界中的非對(duì)象
5.6.3 在混合范式中堅(jiān)持使用module-driven design
第6章 領(lǐng)域?qū)ο蟮纳芷?/h1>
- 聚合式廷,通過(guò)定義清晰的所屬關(guān)系和邊界,并避免混亂芭挽、錯(cuò)綜復(fù)雜的對(duì)象關(guān)系網(wǎng)來(lái)實(shí)現(xiàn)模型的內(nèi)聚滑废。聚合對(duì)于維護(hù)生命周期各個(gè)階段的完整性具有至關(guān)重要的作用。
- 使用factory 創(chuàng)建和重建復(fù)雜對(duì)象和聚合袜爪,從而封裝他們的內(nèi)部結(jié)構(gòu)
- 在生命周期的中間和末尾使用repository蠕趁,來(lái)提供查找和檢索持久化對(duì)象并龐大基礎(chǔ)設(shè)施的手段
6.1 模式:aggregate
AGGREGATE就是一組相關(guān)對(duì)象的集合,我們把它作為數(shù)據(jù)修改的單元辛馆。每個(gè)AGGREGATE
都有一個(gè)根(root)和一個(gè)邊界(boundary)俺陋。邊界定義了AGGREGATE的內(nèi)部都有什么。根則是AGGREGATE所包含的一個(gè)特定ENTITY昙篙。對(duì)AGGREGATE而言腊状,外部對(duì)象只可以引用根,而邊界內(nèi)部的對(duì)象之間則可以互相引用苔可。除根以外的其他ENTITY都有本地標(biāo)識(shí)寿酌,但這些標(biāo)識(shí)只在AGGREGATE內(nèi)部才需要加以區(qū)別,因?yàn)橥獠繉?duì)象除了根ENTITY之外看不到其他對(duì)象硕蛹。
每個(gè)aggregate都有一個(gè)根和邊界。邊界定義了aggregate的內(nèi)部都有什么硕并,根則是aggregate所包含的一個(gè)特定實(shí)體法焰。對(duì)aggregate而言,外部只能引入根倔毙,而邊界內(nèi)部的對(duì)象之間可以互相引用埃仪。
-
固定規(guī)則是指在數(shù)據(jù)變化式必須保持一致性規(guī)則,其涉及aggregate之間的內(nèi)部關(guān)系陕赃。而任何跨越aggregate的規(guī)則將不要求每時(shí)每刻都保持最新的狀態(tài)卵蛉。通過(guò)事件處理、批處理或者其他更新機(jī)制么库,這些依賴會(huì)在一定時(shí)間內(nèi)得以解決傻丝。為了實(shí)現(xiàn)概念上的aggregate,需要對(duì)所有的事務(wù)應(yīng)用一組規(guī)則:
- 根entity 具有全局意識(shí)诉儒,它最終負(fù)責(zé)檢查固定規(guī)則
- 邊界內(nèi)entity 具有本地標(biāo)識(shí)葡缰,這些標(biāo)識(shí)在本地內(nèi)部是唯一的
- aggregate外部的對(duì)象不能引用除entity 之外的任何內(nèi)部對(duì)象。
- 只有aggregte的根才能直接通過(guò)數(shù)據(jù)庫(kù)查詢獲取,所有其他的對(duì)象必須通過(guò)遍歷關(guān)聯(lián)獲取泛释。
- aggregate內(nèi)部的對(duì)象可以保持對(duì)其他aggregate的引用
- 刪除操作必須一次刪除aggregate邊界之內(nèi)的所有對(duì)象
- 當(dāng)提交對(duì)aggregate邊界內(nèi)部的任何修改時(shí)滤愕,整個(gè)aggregate所有的固定規(guī)則必須滿足
我們應(yīng)該將entity和value object分門別類的聚集到aggregate中,并定義每個(gè)aggregate的邊界怜校,在每個(gè)aggregate中间影,選擇一個(gè)entity作為根,并通過(guò)根來(lái)控制對(duì)邊界內(nèi)其他對(duì)象的所有訪問(wèn)茄茁。只允許外部對(duì)象保持對(duì)根的引用魂贬。對(duì)內(nèi)部成員的臨時(shí)引用可以被傳遞出去,但僅在一次操作中有效胰丁。由于根控制訪問(wèn)随橘,因此不能繞過(guò)它來(lái)修改內(nèi)部對(duì)象。這種設(shè)計(jì)有利于確保aggregate中的對(duì)象滿足所有固定規(guī)則锦庸,也可以確保在任何狀態(tài)變化時(shí)aggreaget作為一個(gè)整體滿足固定規(guī)則机蔗。
6.2 模式:factory
- 當(dāng)創(chuàng)建一個(gè)對(duì)象或者創(chuàng)建整個(gè)aggregate時(shí),如果創(chuàng)建工作過(guò)于復(fù)雜甘萧,或者暴露了過(guò)多的內(nèi)部結(jié)構(gòu)萝嘁,則可以使用factory封裝。
- 對(duì)象的創(chuàng)建本身可以是一個(gè)主要操作扬卷。但是被創(chuàng)建的對(duì)象并不適合承擔(dān)復(fù)雜的裝配操作牙言。將這些職責(zé)混在一起可能產(chǎn)生難以理解的拙劣設(shè)計(jì)。讓客戶直接創(chuàng)建對(duì)象有會(huì)讓客戶的設(shè)計(jì)陷入混亂怪得,并且破壞被裝配對(duì)象或aggregate的封裝咱枉,而且導(dǎo)致客戶與被創(chuàng)建對(duì)象的實(shí)現(xiàn)之間產(chǎn)生過(guò)于緊密的耦合。
- 創(chuàng)建復(fù)雜對(duì)象的實(shí)例和aggregate的職責(zé)轉(zhuǎn)交給單獨(dú)的對(duì)象徒恋,這個(gè)對(duì)象并沒(méi)有承擔(dān)領(lǐng)域模型中的規(guī)則蚕断,提供一個(gè)封裝所有復(fù)雜裝配操作的接口,而且這個(gè)接口不需要客戶引用要被實(shí)例化的對(duì)象的具體類入挣。在創(chuàng)建aggregate時(shí)要把它作為一個(gè)整體亿乳,并確保它滿足固定規(guī)則。
- 任何好的工廠需要滿足以下兩個(gè)基本需求
- 每個(gè)創(chuàng)建方法都是原子的径筏,而且要保證被創(chuàng)建對(duì)象和aggregate 的所有固定規(guī)則葛假。
- Factory 應(yīng)該被抽象為所需的類型,而不是所創(chuàng)建的具體類型
6.2.1 選擇factory 及其應(yīng)用位置
6.2.2 有些情況下只需使用構(gòu)造函數(shù)
- 以下情況最好使用構(gòu)造函數(shù)
- 沒(méi)有繼承或者實(shí)現(xiàn)的類
- 客戶關(guān)心的是實(shí)現(xiàn)
- 客戶可以訪問(wèn)所有的屬性
- 構(gòu)造并不復(fù)雜
- 公共構(gòu)造函數(shù)必須遵守與factory 類似的規(guī)則:原子滋恬,必須滿足所有創(chuàng)建對(duì)象的固定規(guī)則
6.2.3 接口設(shè)計(jì)
- 設(shè)計(jì)factory 或factory method需要記住以下兩點(diǎn):
- 每個(gè)操作必須是原子的
- factory 將與其參數(shù)發(fā)生耦合
6.2.4 固定規(guī)則的相關(guān)邏輯放在哪里
- Factory 可以將固定規(guī)則的檢查工作委派給被創(chuàng)建對(duì)象
- 也可以考慮將固定的規(guī)則交給factory 聊训,但是固定規(guī)則的相關(guān)邏輯卻特別不適合放到那些與其他領(lǐng)域?qū)ο箨P(guān)聯(lián)的factory method中。
6.2.5 entity factory 與value object factory
6.2.6 重建已存儲(chǔ)對(duì)象
- 用于重建對(duì)象的factory與用于創(chuàng)建對(duì)象的factory類似夷恍,主要有以下兩點(diǎn)不同
- 用于重建對(duì)象的entity factory不分配新的跟蹤id
- 當(dāng)固定規(guī)則未被滿足時(shí)魔眨,重建對(duì)象的factory采用不同的方式進(jìn)行處理
- factory 封裝了對(duì)象創(chuàng)建和重建時(shí)的生命周期轉(zhuǎn)換媳维。
6.3 模式:repository
- 客戶需要一種有效的方式來(lái)獲取對(duì)已存在的領(lǐng)域?qū)ο蟮囊谩H绻A(chǔ)設(shè)施提供了這方面的便利遏暴,那么開(kāi)發(fā)人員可能會(huì)增加很多可遍歷的關(guān)聯(lián)侄刽,這會(huì)使模型變得非常混亂朋凉。另一方面州丹,開(kāi)發(fā)人員可能使用查詢從數(shù)據(jù)庫(kù)中提取他們所需的數(shù)據(jù),或是直接提取具體的對(duì)象杂彭,而不是通過(guò)AGGREGATE的根來(lái)得到這些對(duì)象墓毒。這樣就導(dǎo)致領(lǐng)域邏輯進(jìn)入查詢和客戶代碼中,而ENTITY和VALUE OBJECT則變成單純的數(shù)據(jù)容器亲怠。采用大多數(shù)處理數(shù)據(jù)庫(kù)訪問(wèn)的技術(shù)復(fù)雜性很快就會(huì)使客戶代碼變得混亂所计,這將導(dǎo)致開(kāi)發(fā)人員簡(jiǎn)化領(lǐng)域?qū)樱罱K使模型變得無(wú)關(guān)緊要团秽。
- 除了通過(guò)根來(lái)遍歷查找對(duì)象這種方法外主胧,禁止其他方法對(duì)于聚合內(nèi)部的任何對(duì)象進(jìn)行訪問(wèn)
- 為每種需要全局訪問(wèn)的對(duì)象創(chuàng)建這個(gè)對(duì)象,這個(gè)對(duì)象相當(dāng)于該類型的所有對(duì)象在內(nèi)存中的這一個(gè)集合的替身习勤,通過(guò)這個(gè)眾所周知的全局接口來(lái)提供訪問(wèn)踪栋。提供添加和刪除對(duì)象的方法,用這些方法來(lái)封裝在數(shù)據(jù)存儲(chǔ)中實(shí)際插入或者刪除的操作图毕。提供根據(jù)具體條件來(lái)挑選對(duì)象的方法夷都,并返回屬性值滿足查詢條件的對(duì)象或者對(duì)象集合,從而將實(shí)際的存儲(chǔ)和查詢技術(shù)封裝起來(lái)予颤。只為那些確實(shí)需要直接訪問(wèn)的aggregate根提供repository囤官。讓客戶始終聚焦于模型,而將所有對(duì)象的存儲(chǔ)和訪問(wèn)操作交給repository蛤虐。
6.3.1 repository 查詢
- 返回某些類型的匯總計(jì)算也符合repository 的概念
- 基于specification 的查詢是一種優(yōu)雅和靈活的查詢方式
6.3.2 開(kāi)發(fā)人員不能忽略的repository的實(shí)現(xiàn)
6.3.3 repository 實(shí)現(xiàn)
- repository概念在很多情況下都使用治拿。可能實(shí)現(xiàn)方法有很多了笆焰,這里只能列出如下一些需要謹(jǐn)記的注意事項(xiàng):
- 對(duì)類型進(jìn)行抽象
- 充分利用與客戶解耦的優(yōu)點(diǎn)
- 將事務(wù)的控制權(quán)交給客戶
6.3.4 在框架內(nèi)工作
- 持久化框架的選擇
6.3.5 repository 和factory 的關(guān)系
- Factory 負(fù)責(zé)處理對(duì)象的生命周期的開(kāi)始,repository 幫助管理生命周期的中間和結(jié)束
-
repository可以委托factory來(lái)創(chuàng)建一個(gè)對(duì)象见坑。
-
客戶使用repository存儲(chǔ)新對(duì)象
6.4 為關(guān)系數(shù)據(jù)庫(kù)設(shè)計(jì)對(duì)象
第七章 使用語(yǔ)言:一個(gè)擴(kuò)展的示例
7.1 貨物運(yùn)輸系統(tǒng)簡(jiǎn)介
7.2 隔離領(lǐng)域:引入應(yīng)用層
- 為了防止領(lǐng)域的職責(zé)與系統(tǒng)的其他部分混雜在一起嚷掠,我們應(yīng)用layered architecture 把領(lǐng)域?qū)觿澐殖鰜?lái)。
- 三個(gè)功能分配給三個(gè)應(yīng)用層類荞驴,應(yīng)用層類是協(xié)調(diào)者
- 跟蹤查詢
- 預(yù)定應(yīng)用
- 事件日志應(yīng)用
7.3 將entity 和 value object 區(qū)別開(kāi)
- 領(lǐng)域?qū)ο蠓诸?/li>
- Customer :entity
- Cargo:entity
- HandlingEvent and Carrier Movement:entity
- Location:entity
- Delivery History:entity
- Delivery Specification:value object
- Role 和其他屬性
7.4 設(shè)計(jì)運(yùn)輸領(lǐng)域中的關(guān)聯(lián)
7.5 Aggregate邊界
7.6 選擇repository
-
在我們的設(shè)計(jì)中不皆,有5個(gè)實(shí)體是aggreagte的根,因此在選擇存儲(chǔ)時(shí)只需要考慮這5個(gè)實(shí)體熊楼,因?yàn)槠渌麑?shí)體都不能有repotitory霹娄。
7.7 場(chǎng)景走查
- 為了復(fù)核這些決策,我們需要經(jīng)常走查場(chǎng)景,以確保能夠有效的解決應(yīng)用問(wèn)題
7.7.1 應(yīng)用程序特性舉例:更新cargo的目的地
7.7.2 應(yīng)用程序特性舉例:重復(fù)業(yè)務(wù)
7.8 對(duì)象的創(chuàng)建
7.8.1 Cargo的factory和構(gòu)造函數(shù)
7.8.2 添加handing event
7.9 停一下犬耻,重構(gòu):Cargo Aggregate的另一種設(shè)計(jì)
7.10 運(yùn)輸模型中的module
7.11 引入新特性:配額檢查
7.11.1 連接兩個(gè)系統(tǒng)
銷售管理系統(tǒng)并不是這里所使用的模型編寫(xiě)的踩晶,如果book application 與它直接交互,那應(yīng)用程序必須適應(yīng)另一個(gè)系統(tǒng)的設(shè)計(jì)枕磁,這將很難保持一個(gè)清晰的module driven design渡蜻,而且會(huì)混淆ubiquitous language。相反我們創(chuàng)建一個(gè)類计济,讓它充當(dāng)我們和銷售管理系統(tǒng)之間的翻譯茸苇。但它不是一種通用機(jī)制,只是對(duì)我們應(yīng)用所需要的特性進(jìn)行翻譯沦寂,并根據(jù)我們的領(lǐng)域模型重新對(duì)這些特性進(jìn)行抽象学密。這個(gè)類將作為一個(gè)anticorruption layer
應(yīng)該使用更有價(jià)值的語(yǔ)言來(lái)重新描述問(wèn)題
7.11.2 進(jìn)一步完善模型:劃分業(yè)務(wù)
重新抽象系統(tǒng)系統(tǒng)領(lǐng)域:我們需要增加貨物類別的知識(shí),以便使模型更加豐富传藏。而且需要與領(lǐng)域?qū)<乙黄疬M(jìn)行頭腦風(fēng)暴活動(dòng)腻暮,以便于抽象出新的概念。
-
Enterprise Segement:企業(yè)部門單元
Allcation Checker 將充當(dāng)Enterprise Segment 與外部系統(tǒng)類別名稱之間的翻譯漩氨。Cargo Repository還必須提供一種基于Enterprise Segement的查詢西壮。
-
發(fā)現(xiàn)問(wèn)題
7.11.3 性能優(yōu)化
7.12 小結(jié)
第三部分 通過(guò)重構(gòu)加深理解
- 當(dāng)然我們面臨真正的挑戰(zhàn)是找到深層次的模型,這個(gè)模型不僅能捕捉到領(lǐng)域?qū)<业奈⒚铌P(guān)注點(diǎn)叫惊,還可以驅(qū)動(dòng)切實(shí)可行的驅(qū)動(dòng)設(shè)計(jì)款青。
- 要想成功的開(kāi)發(fā)出實(shí)用的模型,需要注意以下三點(diǎn):
- 復(fù)雜巧妙的領(lǐng)域模型是可以實(shí)現(xiàn)的霍狰,也值得我們?nèi)セㄙM(fèi)力氣實(shí)現(xiàn)的
- 這樣的模型離開(kāi)不斷的重構(gòu)是很難開(kāi)發(fā)出來(lái)的抡草,重構(gòu)需要領(lǐng)域?qū)<液蜔釔?ài)學(xué)習(xí)領(lǐng)域知識(shí)的開(kāi)發(fā)人員密切參與進(jìn)來(lái)的
- 要實(shí)現(xiàn)并有效的運(yùn)用模型,需要精通設(shè)計(jì)技巧
深層領(lǐng)域模型能夠穿越領(lǐng)域表象蔗坯,清晰的表達(dá)出專家們的主要關(guān)注點(diǎn)以及最相關(guān)的知識(shí)康震。
恰當(dāng)反應(yīng)領(lǐng)域的模型通常都具有功能多樣性、簡(jiǎn)單易用和解釋力強(qiáng)的特性
第8章 突破
8.1 一個(gè)關(guān)于突破的故事
8.1.1 華而不實(shí)的模型
8.1.2 突破
- loan 股份和facility 的股份可以在互不影響的情況下獨(dú)立發(fā)生變化
- 需求發(fā)生變化宾濒,具體參考P134 內(nèi)容
8.1.3 更深層模型
-
股份抽象模型
-
使用share pie的loan 模型
8.1.4 冷靜決策
- 最后銀團(tuán)貸款項(xiàng)目進(jìn)行了重構(gòu)
8.1.5 成果
8.2 機(jī)遇
- 當(dāng)突破帶來(lái)深層次模型時(shí)腿短,通常會(huì)讓人感到不安。與大部分重構(gòu)相比绘梦,這種變化的回報(bào)更多橘忱,風(fēng)險(xiǎn)也更高。而且突破出現(xiàn)的時(shí)機(jī)可能不合時(shí)宜卸奉。
8.3 關(guān)注根本
- 不要試圖制造突破钝诚,那只會(huì)使項(xiàng)目陷入困境。通常榄棵,只有實(shí)現(xiàn)許多適度的重構(gòu)才有可能出現(xiàn)突破凝颇。在大部分的時(shí)間里潘拱,我們都在進(jìn)行微小的改進(jìn)。而在這種持續(xù)改進(jìn)中深層次模型含義也逐漸顯現(xiàn)拧略。
- 要為突破做準(zhǔn)備芦岂,應(yīng)專注于知識(shí)消化過(guò)程,同時(shí)也要逐漸建立健壯的ubiquitous language辑鲤。尋找那些重要的領(lǐng)域概念盔腔,并在模型中清晰地表達(dá)出來(lái)。精化模型月褥,使其更具有柔性弛随。提煉模型。利用這些更容易掌握的手段使模型變得更清晰宁赤,這通常會(huì)帶來(lái)突破舀透。
8.4 后記:越來(lái)越多的新理解
第9章 將隱式概念轉(zhuǎn)換為顯示概念
- 若開(kāi)發(fā)人員識(shí)別出設(shè)計(jì)中隱含的某個(gè)概念或者討論中受到啟發(fā)而發(fā)現(xiàn)一個(gè)概念時(shí),就會(huì)對(duì)領(lǐng)域模型和相應(yīng)的代碼進(jìn)行許多轉(zhuǎn)換决左,在模型中添加一個(gè)或多個(gè)對(duì)象和關(guān)系時(shí)愕够,從而將此概念顯示的表達(dá)出來(lái)
9.1 概念挖掘
9.1.1 傾聽(tīng)語(yǔ)言
- 傾聽(tīng)領(lǐng)域?qū)<沂褂玫恼Z(yǔ)言。有沒(méi)有一些術(shù)語(yǔ)能夠簡(jiǎn)潔的表達(dá)出復(fù)雜的概念佛猛?他們有沒(méi)有糾正過(guò)你的用詞惑芭?當(dāng)你使用某些特定詞語(yǔ)的時(shí)候,他們臉上是否已經(jīng)不再流露出迷惑的表情继找?這些都暗示了某個(gè)概念可以改進(jìn)模型遂跟。
-
運(yùn)輸模型
9.1.2 檢查不足之處
-
利息模型
-
重構(gòu)后的深層模型
-
更深層次模型
-
重構(gòu)后的深層模型
9.1.3 思考矛盾之處
9.1.4 查閱書(shū)籍
9.1.5 嘗試、再嘗試
9.2 如何為那些不太明顯的概念建模
9.2.1 顯示的約束
- 約束是模型概念中非常重要的類別婴渡。它們通常是隱含的幻锁,將它們顯示的表現(xiàn)出來(lái)可以極大的提高設(shè)計(jì)質(zhì)量
9.2.2 將過(guò)程建模為領(lǐng)域?qū)ο?/h3>
- 我們討論的是存在領(lǐng)域中的過(guò)程,我們必須在模型中把這些過(guò)程表示出來(lái)边臼。否則當(dāng)這些過(guò)程顯露出來(lái)時(shí)哄尔,往往會(huì)使對(duì)象設(shè)計(jì)變得笨拙
9.2.3 模式:specification
9.2.4 specification的應(yīng)用和實(shí)現(xiàn)
- specification最有價(jià)值的地方在于他可以將不同的應(yīng)用功能統(tǒng)一起來(lái)。出于以下三個(gè)目的中的一個(gè)或者多個(gè)柠并,我們需要指定對(duì)象的狀態(tài)
- 驗(yàn)證對(duì)象岭接,檢查它是否滿足某些需求或者已經(jīng)為實(shí)現(xiàn)某個(gè)目標(biāo)做好了準(zhǔn)備。
- 從集合中選擇一個(gè)對(duì)象
- 指定在創(chuàng)建對(duì)象時(shí)必須滿足某種需求
第10章 柔性設(shè)計(jì)
- 為了使項(xiàng)目能夠隨著開(kāi)發(fā)工作的進(jìn)行加速前進(jìn)臼予,而 不會(huì)由于它自己的老化停滯不前亿傅,設(shè)計(jì)必須讓人們樂(lè)于使用,而且易于做出修改瘟栖。這就是柔性設(shè)計(jì)(supple design)。
- 柔性設(shè)計(jì)是對(duì)深層模型的補(bǔ)充
10.1 模式:intention-revealing interfaces
-
前一章節(jié)深入探討了對(duì)于規(guī)則和計(jì)算進(jìn)行顯示的建模谅阿,實(shí)現(xiàn)這樣的對(duì)象要求我們深入理解計(jì)算或者規(guī)則的大部分細(xì)節(jié)半哟。對(duì)象的強(qiáng)大功能就是把細(xì)節(jié)隱藏起來(lái)酬滤,如此一來(lái),客戶代碼就能很簡(jiǎn)單寓涨,而且可以用高層概念來(lái)解釋盯串。
2.一些有助于獲得柔性設(shè)計(jì)的模式
Kent Beck 曾經(jīng)提出通過(guò)intention - revealing selector (釋意命名選擇器)來(lái)選擇方法的名稱,使名稱表達(dá)其目的戒良。類型名稱体捏、方法名稱和參數(shù)名稱組合在一起,共同形成了一個(gè)intention-revealing interface糯崎。
在命名類和操作時(shí)几缭,要描述他們的效果和目的,而不是表達(dá)他們是通過(guò)何種方式達(dá)到目的的沃呢。這樣可以使用客戶開(kāi)發(fā)人員不必去理解內(nèi)部細(xì)節(jié)年栓。這些名稱應(yīng)該與ubiquitous language 保持一致,便于團(tuán)隊(duì)人員可以迅速推斷出他們的意義薄霜。在創(chuàng)建一個(gè)行為前為它編寫(xiě)一個(gè)測(cè)試某抓,這樣可以站在客戶開(kāi)發(fā)人員的角度思考他們。
10.2 模式:side-effect-free function
- 任何對(duì)未來(lái)操作產(chǎn)生影響的系統(tǒng)狀態(tài)改變都可以稱為副作用
- 多個(gè)規(guī)則的相互作用或者計(jì)算的組合產(chǎn)生的結(jié)果是很預(yù)測(cè)的惰瓜。開(kāi)發(fā)人員在調(diào)用一個(gè)操作時(shí)否副,為了預(yù)測(cè)操作的結(jié)果,必須理解它的實(shí)現(xiàn)以及它所調(diào)用其它方法的實(shí)現(xiàn)崎坊。如果不得不“揭開(kāi)接口的面紗”备禀,那么接口的抽象作用就受到了限制。如果沒(méi)有了可以安全的預(yù)見(jiàn)結(jié)果的抽象流强,開(kāi)發(fā)人員就必須限制“組合爆炸”痹届,這就限制了系統(tǒng)行為的豐富性。
- 返回結(jié)果而不產(chǎn)生副作用的操作稱之為“函數(shù)”打月。
- 把命令和查詢嚴(yán)格的放在不同的模型中队腐。確保導(dǎo)致?tīng)顟B(tài)改變的方法不返回領(lǐng)域數(shù)據(jù),并盡可能的保持簡(jiǎn)單奏篙。在不引起任何副作用的方法中執(zhí)行所有查詢和計(jì)算柴淘。
5.總有一些替代的模型和設(shè)計(jì),他們不要求對(duì)現(xiàn)有版本進(jìn)行任何修改秘通。相反为严,他們創(chuàng)建并返回一個(gè)value object用于表示計(jì)算結(jié)果
- 盡可能的把程序的邏輯放在函數(shù)中,因而函數(shù)是只產(chǎn)生結(jié)果而不會(huì)產(chǎn)生副作用的操作肺稀。嚴(yán)格的把命令隔離到不返回領(lǐng)域信息的第股,非常簡(jiǎn)單的操作中。當(dāng)發(fā)現(xiàn)一個(gè)非常適合承擔(dān)復(fù)雜邏輯的概念時(shí)话原,就把復(fù)雜的邏輯轉(zhuǎn)移到value object中夕吻,這樣就可以進(jìn)一步的控制副作用诲锹。
10.3 模式:assertion
- 契約式設(shè)計(jì),向前推進(jìn)了一小步涉馅。通過(guò)給出類和方法 的斷言使開(kāi)發(fā)人員知道了肯定發(fā)生的結(jié)果归园。簡(jiǎn)而言之,后置條件描述了一個(gè)操作的副作用稚矿,也就是調(diào)用一個(gè)方法之后必然發(fā)生的結(jié)果庸诱。前置條件就像是合同條款,即為了滿足后置條件而必須要滿足的前置條件晤揣。類的固定規(guī)則規(guī)定了在操作結(jié)束時(shí)對(duì)象的狀態(tài)桥爽。也可以將aggregate作為一個(gè)整體來(lái)為它聲明規(guī)定規(guī)則,這些都是嚴(yán)格定義的完整性規(guī)則碉渡。
- 把操作的后置條件和類以及aggregate的固定規(guī)則表達(dá)清楚聚谁。如果在你的編程語(yǔ)言中不能直接編寫(xiě)斷言,那么就把它寫(xiě)成自動(dòng)的單元測(cè)試滞诺。還可以把它寫(xiě)在文檔和圖中形导。
10.4 模式:conceptual contour
- conceptual contour:概念輪廓
- 把設(shè)計(jì)元素(操作,接口习霹,類以及aggregate)分解為內(nèi)聚的單元朵耕,在過(guò)程中,你對(duì)于領(lǐng)域中一切重要的劃分的直觀認(rèn)知也需要考慮在內(nèi)淋叶。在連續(xù)的重構(gòu)中觀察發(fā)生的變化和保證穩(wěn)定的規(guī)律性阎曹,并尋找能夠解釋這些變化模式的底層conceptual contour。使模型與領(lǐng)域中那些一致的方面相匹配煞檩。
10.5 模式:standalone class
- module和aggregate 目的是為了限制互相依賴的關(guān)系網(wǎng)处嫌。
- 低耦合是對(duì)象設(shè)計(jì)的一個(gè)基本要素。盡一切可能保持低耦合斟湃,把其它所有無(wú)關(guān)概念提取到對(duì)象之外熏迹。這樣類就變得完全獨(dú)立了,這就可以使我們單獨(dú)研究和理解他們凝赛。每個(gè)這樣獨(dú)立類都極大的減輕因理解module而帶來(lái)的負(fù)擔(dān)注暗。
10.6 模式:closure of operation (閉合操作)
- 在適當(dāng)?shù)那樾蜗拢诙x操作時(shí)墓猎,讓它的參數(shù)類型與返回類型保持一致捆昏。如果實(shí)現(xiàn)者的狀態(tài)在計(jì)算中會(huì)用到,那么實(shí)現(xiàn)者實(shí)際上就是操作的一個(gè)參數(shù)毙沾。因此參數(shù)和返回值應(yīng)該與實(shí)現(xiàn)者有相同的類型骗卜。這樣的操作就是在該類型的實(shí)例集合中的閉合操作。閉合操作提供了一個(gè)高層接口,同時(shí)又不會(huì)引入其他概念的任何依賴寇仓。
10.7 聲明式設(shè)計(jì)
10.8 聲明式設(shè)計(jì)風(fēng)格
10.9 切入問(wèn)題的角度
10.9.1 分割子領(lǐng)域
10.9.2 盡可能利用已有的形式
第11章 應(yīng)用分析模式
- 分析模式是一種概念集合勇皇,用來(lái)表示業(yè)務(wù)建模中的常見(jiàn)結(jié)構(gòu)。它可能只與一個(gè)領(lǐng)域有關(guān)焚刺,也可能跨域多個(gè)領(lǐng)域。
第12章:將設(shè)計(jì)模式應(yīng)用于模型
12.1 模式:strategy
12.2 模式:composite
12.3 為什么沒(méi)有介紹flyweight
第13章 通過(guò)重構(gòu)得到更深次的理解
- 有三件事情是必須要關(guān)注的:
- 以領(lǐng)域?yàn)楸?/li>
- 用一種不同的方式看待事物
- 始終堅(jiān)持與領(lǐng)域?qū)<覍?duì)話
13.1 開(kāi)始重構(gòu)
13.2 探索團(tuán)隊(duì)
13.3 借鑒先前經(jīng)驗(yàn)
13.4 針對(duì)開(kāi)發(fā)人員的設(shè)計(jì)
13.5 重構(gòu)的時(shí)機(jī)
13.6 危機(jī)就是機(jī)遇
第四部分 戰(zhàn)略設(shè)計(jì)
- 三大主題:上下文门烂、精煉和大型結(jié)構(gòu)
第14章 保持模型的完整性
- 大型系統(tǒng)領(lǐng)域模型的完全統(tǒng)一即不可行乳愉,也不劃算
- 既然無(wú)法維護(hù)一個(gè)涵蓋整個(gè)企業(yè)的統(tǒng)一模型,那就不要再受到這種思路的限制屯远。通過(guò)預(yù)先決定什么應(yīng)該統(tǒng)一蔓姚,并實(shí)際認(rèn)識(shí)到什么不能統(tǒng)一,我們就能創(chuàng)建一個(gè)清晰的,共同的視圖
- 我們需要使用一種方式來(lái)標(biāo)記出來(lái)不同模型之間的邊界和關(guān)系。
- bounded context(限界上下文)定義了每個(gè)模型的應(yīng)用范圍割笙,而context map(上下文圖)則給出來(lái)項(xiàng)目上下文以及他們之間的關(guān)系的總體視圖蒙畴。
- 在這個(gè)穩(wěn)定的基礎(chǔ)上,我們就可以開(kāi)始實(shí)施那些在界定和關(guān)聯(lián)context方面更有效的策略了-從通過(guò)共享內(nèi)核來(lái)緊密關(guān)聯(lián)上下文蝇棉,到那些各行其道
14.1 模型:bounded context
- 任何大型項(xiàng)目都會(huì)存在多個(gè)模型。而當(dāng)基于不同模型的代碼被組合在一起后,軟件就會(huì)出現(xiàn)bug恬砂、變得不可靠和難以理解。團(tuán)隊(duì)成員之間的溝通變的混亂蓬痒。人們往往弄不清楚一個(gè)模型不應(yīng)該在哪個(gè)上下文中使用
- 一個(gè)模型只在一個(gè)上下文使用泻骤。
- 明確定義模型所應(yīng)用的上下文。根據(jù)團(tuán)隊(duì)的組織梧奢,軟件系統(tǒng)的各個(gè)部分的用法以及物理表現(xiàn)(代碼以及數(shù)據(jù)庫(kù)模型等)來(lái)設(shè)置模型的邊界狱掂。在這些邊界中嚴(yán)格保持模型的一致性,而不要受到邊界之外問(wèn)題的干擾和混亂亲轨。
- bounded context不是module
- 將不同模型的元素組合在一起可能會(huì)引發(fā)兩類問(wèn)題:重復(fù)的概念和假同源趋惨。重復(fù)的概念指的是兩個(gè)模型元素實(shí)際上表示同一個(gè)概念。假同源指的是使用相同屬于的兩個(gè)人認(rèn)為是在討論同一件事瓶埋,但是實(shí)際上不是這樣的希柿。
14.2 模式:continuous integration
- 當(dāng)很多人在同一個(gè)bounded context中工作時(shí),模型很容易發(fā)生分裂养筒。如果將系統(tǒng)分解為更小的context曾撤,最終又難以保持集成度和一致性。
- continuous integration是指把一個(gè)上下文中的所有工作足夠頻繁的合并到一起晕粪,并使他們保持一致挤悉,以便當(dāng)模型發(fā)生分裂時(shí),可以迅速發(fā)現(xiàn)并糾正問(wèn)題巫湘。
- 團(tuán)隊(duì)成員之間通過(guò)經(jīng)常溝通來(lái)保證概念的集成装悲。團(tuán)隊(duì)成員必須對(duì)不斷變化的模型形成一個(gè)共同的理解昏鹃。
- 建立一個(gè)把所有代碼和其他實(shí)現(xiàn)工件頻繁的合并到一起的工程,并通過(guò)自動(dòng)化測(cè)試來(lái)快速查明模型的分類問(wèn)題诀诊。嚴(yán)格堅(jiān)持使用ubiquitous lanuage洞渤,以便在不同人的頭腦中演變出不同的概念時(shí),使所有人對(duì)模型達(dá)成一個(gè)共識(shí)属瓣。
14.3 模式:context map
- 其他團(tuán)隊(duì)中的人員并不是十分清楚context的邊界载迄,他們會(huì)不知不覺(jué)中做出一些更改,從而是邊界變得模糊或者互聯(lián)變得復(fù)雜抡蛙。當(dāng)不同的上下文必須互相連接時(shí)护昧,他們可能會(huì)互相重疊。
- 通過(guò)定義不同的上下文之間的關(guān)系粗截,并在項(xiàng)目中創(chuàng)建一個(gè)所有上下文的全局視圖惋耙,可以減少混亂
- 識(shí)別在項(xiàng)目中起作用的每個(gè)模型,并定義其bounded context熊昌。這包括非面向?qū)ο笞酉到y(tǒng)的隱含模型绽榛。為每個(gè)bounded contetx命名。并把名稱添加到ubiquitous language中浴捆。描述模型之間的聯(lián)系點(diǎn)蒜田,明確所有通信需要的轉(zhuǎn)換,并突出任何共享的內(nèi)容选泻。先將當(dāng)前的情況描繪出來(lái)冲粤,以后再做改變。
14.3.1 測(cè)試context的邊界
- 對(duì)各個(gè)bounded context的聯(lián)系點(diǎn)的測(cè)試特別重要
14.3.2 context map的組織和文檔化
- 兩個(gè)重點(diǎn)
- bounded context應(yīng)該有名稱页眯,以便于可以討論他們梯捕。這些名稱應(yīng)該被添加到團(tuán)隊(duì)的ubiquitous language中
- 每個(gè)人都應(yīng)該知道邊界在哪里,而且應(yīng)該能夠分辨出任何代碼段的context窝撵,或者任何情況的context
- 一旦定義了counded context傀顾,那么把不同的上下文的代碼隔離到不同的module中就再自然不過(guò)濾。
- 我們可以用命名規(guī)范來(lái)表明這一點(diǎn)碌奉,后者使用其他簡(jiǎn)單且不會(huì)產(chǎn)生混淆的機(jī)制
14.4 bounded context之間的關(guān)系
14.5 模式:shared kernel
- 當(dāng)不同的團(tuán)隊(duì)開(kāi)發(fā)一些緊密相關(guān)的應(yīng)用程序時(shí)短曾,如果團(tuán)隊(duì)之間不進(jìn)行協(xié)調(diào),即使短時(shí)間內(nèi)能夠取得快速進(jìn)展赐劣,但他們開(kāi)發(fā)的產(chǎn)品可能無(wú)法結(jié)合到一起嫉拐。最后可能不得不耗費(fèi)大量精力在轉(zhuǎn)換層上,并且頻繁的進(jìn)行改動(dòng)魁兼,不如一開(kāi)始就使用continuous integration那么省心省力婉徘,同時(shí)這也造成重復(fù)工農(nóng)工作,并且無(wú)法使用公共的ubiquitous language所帶來(lái)的好處
- 從領(lǐng)域模型中選出兩個(gè)團(tuán)隊(duì)都統(tǒng)一共享的一個(gè)子集。當(dāng)然盖呼,除了這個(gè)模型子集以外儒鹿,還包括與該模型部分相關(guān)的代碼子集,或數(shù)據(jù)庫(kù)設(shè)計(jì)的子集几晤。這部分明確共享的內(nèi)容具有特殊的地位约炎,一個(gè)團(tuán)隊(duì)在沒(méi)有與另外一個(gè)團(tuán)隊(duì)上商量的情況下不應(yīng)該擅自修改它。
- 共享內(nèi)核中必須集成自動(dòng)測(cè)試套件蟹瘾,因?yàn)樾薷墓蚕韮?nèi)核時(shí)章钾,必須通過(guò)兩個(gè)團(tuán)隊(duì)的所有測(cè)試
- shared kernel 通常是core domain,或者是一組generic subdomain(通用子領(lǐng)域)热芹,也可能是二者兼有。
14.6 模式:customer/supplier development team
- 在兩個(gè)團(tuán)隊(duì)之間建立一種米孔雀的客戶/供應(yīng)商關(guān)系惨撇。在計(jì)劃會(huì)議中伊脓,下游團(tuán)隊(duì)相當(dāng)于上游團(tuán)隊(duì)的客戶。根據(jù)下游團(tuán)隊(duì)的需求來(lái)協(xié)商需要執(zhí)行的任務(wù)并為這些任務(wù)做預(yù)算魁衙,以便于每個(gè)人都知道雙方的約定和進(jìn)度
- 兩個(gè)團(tuán)隊(duì)共同開(kāi)發(fā)自動(dòng)化驗(yàn)收測(cè)試报腔,用于驗(yàn)證逾期的接口,把這些測(cè)試添加到上游團(tuán)隊(duì)的測(cè)試套件中剖淀,以便作為其持續(xù)集成的一部分來(lái)運(yùn)行纯蛾。這些測(cè)試使上游團(tuán)隊(duì)在做出修改時(shí),不比擔(dān)心對(duì)于上游團(tuán)隊(duì)產(chǎn)生副作用纵隔。
14.7 模式:conformist(跟隨者)
- 通過(guò)嚴(yán)格遵從上游團(tuán)隊(duì)的模型翻诉,可以消除在bounded context之間進(jìn)行轉(zhuǎn)換的復(fù)雜性。盡管這會(huì)限制下游設(shè)計(jì)人員的風(fēng)格捌刮,而且可能不會(huì)得到理想的應(yīng)用程序模型碰煌,單選擇conformity模式可以極大的簡(jiǎn)化集成。此外绅作,這樣還可以與供應(yīng)商團(tuán)隊(duì)共享ubiquitous language芦圾。供應(yīng)商處于統(tǒng)治地位,因此最好使溝通變?nèi)菀锥砣稀K麄儚睦髁x的角度出發(fā)个少,會(huì)與你分享信息
14.8 模式:anticorruption layer
smart ui 與DDD對(duì)比
種方式應(yīng)該與其形式和歷史無(wú)關(guān)倍靡。要格外注意那些需要通過(guò)屬性來(lái)匹配對(duì)象的需求。在定義標(biāo)識(shí)操作時(shí)课舍,要確保這種操作為每個(gè)對(duì)象生成唯一的結(jié)果塌西,這可以通過(guò)附加一個(gè)保證唯一性的符號(hào)來(lái)實(shí)現(xiàn)。這種定義標(biāo)識(shí)的方法可能來(lái)自外部筝尾,也可能是由系統(tǒng)創(chuàng)建的任意標(biāo)識(shí)符捡需,但它在模型中必須是唯一的標(biāo)識(shí)。模型必須定義出“符合什么條件才算是相同的事物”
-
在大多數(shù)開(kāi)發(fā)系統(tǒng)中哟玷,在一個(gè)領(lǐng)域?qū)ο蠛屯獠抠Y源之間直接建立一個(gè)接口是很別扭的。我們可以利用一個(gè)facade將這樣的service包裝起來(lái)一也,這樣外觀可能以模型作為輸入术吗,并返回一個(gè)“Fund Transfer”對(duì)象。
5.4.2 粒度
- service可以控制領(lǐng)域?qū)又械慕涌诘牧6润锱剩⑶冶苊饪蛻舳伺centity和value object耦合子漩。
- 由于應(yīng)用層負(fù)責(zé)對(duì)領(lǐng)域?qū)ο蟮男袨檫M(jìn)行協(xié)調(diào),因此細(xì)粒度的領(lǐng)域?qū)ο罂赡軙?huì)把領(lǐng)域?qū)拥闹R(shí)蔓延到應(yīng)用層或者用戶界面代碼當(dāng)中舆蝴。
- 明智地引入領(lǐng)域?qū)臃?wù)有助于在應(yīng)用層和領(lǐng)域?qū)又g保持一條明確的界限
5.4.3 對(duì)Service 的訪問(wèn)
5.5 模式:module谦絮,也稱為package
-
module為人們提供兩種觀察模型的方式,一是可以在module中查詢細(xì)節(jié),而不會(huì)被整個(gè)模型淹沒(méi)洁仗,二是觀察module之間的關(guān)系层皱,而考慮其內(nèi)部細(xì)節(jié)。
- module的名稱應(yīng)該是ubiquitous language中的術(shù)語(yǔ)赠潦。module及其名稱應(yīng)該反映出領(lǐng)域的深層知識(shí)叫胖。
- 如果一個(gè)類依賴另一個(gè)包中的類,但是本地module對(duì)于該module并沒(méi)有概念上的依賴關(guān)系祭椰,那么或許應(yīng)該移動(dòng)一個(gè)類臭家,或者考慮重新組織module
5.5.1 敏捷的module
- MODULE需要與模型的其他部分一同演變。這意味著MODULE的重構(gòu)必須與模型和代碼一起進(jìn)行方淤。但這種重構(gòu)通常不會(huì)發(fā)生钉赁。更改MODULE可能需要大范圍地更新代碼。這些更改可能會(huì)對(duì)團(tuán)隊(duì)溝通起到破壞作用携茂,甚至?xí)恋K開(kāi)發(fā)工具(如源代碼控制系統(tǒng))的使用你踩。因此,MODULE結(jié)構(gòu)和名稱往往反映了模型的較早形式,而類則不是這樣
5.5.2 通過(guò)基礎(chǔ)設(shè)施打包時(shí)存在的隱患
- 除非真正的有必要將代碼分布到不同的機(jī)器上带膜,否則就把實(shí)現(xiàn)單一概念對(duì)象的所有代碼放在同一模塊中
- 利用打包把領(lǐng)域?qū)訌钠渌a中分離出來(lái)吩谦,否則,就盡可能讓領(lǐng)域開(kāi)發(fā)人員自由決定對(duì)象的打包方式膝藕,以便于支持他們的模型和設(shè)計(jì)選擇
5.6 建模范式
5.6.1 對(duì)象方式流行的原因
5.6.2對(duì)象世界中的非對(duì)象
5.6.3 在混合范式中堅(jiān)持使用module-driven design
第6章 領(lǐng)域?qū)ο蟮纳芷?/h1>
- 聚合式廷,通過(guò)定義清晰的所屬關(guān)系和邊界,并避免混亂芭挽、錯(cuò)綜復(fù)雜的對(duì)象關(guān)系網(wǎng)來(lái)實(shí)現(xiàn)模型的內(nèi)聚滑废。聚合對(duì)于維護(hù)生命周期各個(gè)階段的完整性具有至關(guān)重要的作用。
- 使用factory 創(chuàng)建和重建復(fù)雜對(duì)象和聚合袜爪,從而封裝他們的內(nèi)部結(jié)構(gòu)
- 在生命周期的中間和末尾使用repository蠕趁,來(lái)提供查找和檢索持久化對(duì)象并龐大基礎(chǔ)設(shè)施的手段
6.1 模式:aggregate
AGGREGATE就是一組相關(guān)對(duì)象的集合,我們把它作為數(shù)據(jù)修改的單元辛馆。每個(gè)AGGREGATE
都有一個(gè)根(root)和一個(gè)邊界(boundary)俺陋。邊界定義了AGGREGATE的內(nèi)部都有什么。根則是AGGREGATE所包含的一個(gè)特定ENTITY昙篙。對(duì)AGGREGATE而言腊状,外部對(duì)象只可以引用根,而邊界內(nèi)部的對(duì)象之間則可以互相引用苔可。除根以外的其他ENTITY都有本地標(biāo)識(shí)寿酌,但這些標(biāo)識(shí)只在AGGREGATE內(nèi)部才需要加以區(qū)別,因?yàn)橥獠繉?duì)象除了根ENTITY之外看不到其他對(duì)象硕蛹。
每個(gè)aggregate都有一個(gè)根和邊界。邊界定義了aggregate的內(nèi)部都有什么硕并,根則是aggregate所包含的一個(gè)特定實(shí)體法焰。對(duì)aggregate而言,外部只能引入根倔毙,而邊界內(nèi)部的對(duì)象之間可以互相引用埃仪。
-
固定規(guī)則是指在數(shù)據(jù)變化式必須保持一致性規(guī)則,其涉及aggregate之間的內(nèi)部關(guān)系陕赃。而任何跨越aggregate的規(guī)則將不要求每時(shí)每刻都保持最新的狀態(tài)卵蛉。通過(guò)事件處理、批處理或者其他更新機(jī)制么库,這些依賴會(huì)在一定時(shí)間內(nèi)得以解決傻丝。為了實(shí)現(xiàn)概念上的aggregate,需要對(duì)所有的事務(wù)應(yīng)用一組規(guī)則:
- 根entity 具有全局意識(shí)诉儒,它最終負(fù)責(zé)檢查固定規(guī)則
- 邊界內(nèi)entity 具有本地標(biāo)識(shí)葡缰,這些標(biāo)識(shí)在本地內(nèi)部是唯一的
- aggregate外部的對(duì)象不能引用除entity 之外的任何內(nèi)部對(duì)象。
- 只有aggregte的根才能直接通過(guò)數(shù)據(jù)庫(kù)查詢獲取,所有其他的對(duì)象必須通過(guò)遍歷關(guān)聯(lián)獲取泛释。
- aggregate內(nèi)部的對(duì)象可以保持對(duì)其他aggregate的引用
- 刪除操作必須一次刪除aggregate邊界之內(nèi)的所有對(duì)象
- 當(dāng)提交對(duì)aggregate邊界內(nèi)部的任何修改時(shí)滤愕,整個(gè)aggregate所有的固定規(guī)則必須滿足
我們應(yīng)該將entity和value object分門別類的聚集到aggregate中,并定義每個(gè)aggregate的邊界怜校,在每個(gè)aggregate中间影,選擇一個(gè)entity作為根,并通過(guò)根來(lái)控制對(duì)邊界內(nèi)其他對(duì)象的所有訪問(wèn)茄茁。只允許外部對(duì)象保持對(duì)根的引用魂贬。對(duì)內(nèi)部成員的臨時(shí)引用可以被傳遞出去,但僅在一次操作中有效胰丁。由于根控制訪問(wèn)随橘,因此不能繞過(guò)它來(lái)修改內(nèi)部對(duì)象。這種設(shè)計(jì)有利于確保aggregate中的對(duì)象滿足所有固定規(guī)則锦庸,也可以確保在任何狀態(tài)變化時(shí)aggreaget作為一個(gè)整體滿足固定規(guī)則机蔗。
6.2 模式:factory
- 當(dāng)創(chuàng)建一個(gè)對(duì)象或者創(chuàng)建整個(gè)aggregate時(shí),如果創(chuàng)建工作過(guò)于復(fù)雜甘萧,或者暴露了過(guò)多的內(nèi)部結(jié)構(gòu)萝嘁,則可以使用factory封裝。
- 對(duì)象的創(chuàng)建本身可以是一個(gè)主要操作扬卷。但是被創(chuàng)建的對(duì)象并不適合承擔(dān)復(fù)雜的裝配操作牙言。將這些職責(zé)混在一起可能產(chǎn)生難以理解的拙劣設(shè)計(jì)。讓客戶直接創(chuàng)建對(duì)象有會(huì)讓客戶的設(shè)計(jì)陷入混亂怪得,并且破壞被裝配對(duì)象或aggregate的封裝咱枉,而且導(dǎo)致客戶與被創(chuàng)建對(duì)象的實(shí)現(xiàn)之間產(chǎn)生過(guò)于緊密的耦合。
- 創(chuàng)建復(fù)雜對(duì)象的實(shí)例和aggregate的職責(zé)轉(zhuǎn)交給單獨(dú)的對(duì)象徒恋,這個(gè)對(duì)象并沒(méi)有承擔(dān)領(lǐng)域模型中的規(guī)則蚕断,提供一個(gè)封裝所有復(fù)雜裝配操作的接口,而且這個(gè)接口不需要客戶引用要被實(shí)例化的對(duì)象的具體類入挣。在創(chuàng)建aggregate時(shí)要把它作為一個(gè)整體亿乳,并確保它滿足固定規(guī)則。
- 任何好的工廠需要滿足以下兩個(gè)基本需求
- 每個(gè)創(chuàng)建方法都是原子的径筏,而且要保證被創(chuàng)建對(duì)象和aggregate 的所有固定規(guī)則葛假。
- Factory 應(yīng)該被抽象為所需的類型,而不是所創(chuàng)建的具體類型
6.2.1 選擇factory 及其應(yīng)用位置
6.2.2 有些情況下只需使用構(gòu)造函數(shù)
- 以下情況最好使用構(gòu)造函數(shù)
- 沒(méi)有繼承或者實(shí)現(xiàn)的類
- 客戶關(guān)心的是實(shí)現(xiàn)
- 客戶可以訪問(wèn)所有的屬性
- 構(gòu)造并不復(fù)雜
- 公共構(gòu)造函數(shù)必須遵守與factory 類似的規(guī)則:原子滋恬,必須滿足所有創(chuàng)建對(duì)象的固定規(guī)則
6.2.3 接口設(shè)計(jì)
- 設(shè)計(jì)factory 或factory method需要記住以下兩點(diǎn):
- 每個(gè)操作必須是原子的
- factory 將與其參數(shù)發(fā)生耦合
6.2.4 固定規(guī)則的相關(guān)邏輯放在哪里
- Factory 可以將固定規(guī)則的檢查工作委派給被創(chuàng)建對(duì)象
- 也可以考慮將固定的規(guī)則交給factory 聊训,但是固定規(guī)則的相關(guān)邏輯卻特別不適合放到那些與其他領(lǐng)域?qū)ο箨P(guān)聯(lián)的factory method中。
6.2.5 entity factory 與value object factory
6.2.6 重建已存儲(chǔ)對(duì)象
- 用于重建對(duì)象的factory與用于創(chuàng)建對(duì)象的factory類似夷恍,主要有以下兩點(diǎn)不同
- 用于重建對(duì)象的entity factory不分配新的跟蹤id
- 當(dāng)固定規(guī)則未被滿足時(shí)魔眨,重建對(duì)象的factory采用不同的方式進(jìn)行處理
- factory 封裝了對(duì)象創(chuàng)建和重建時(shí)的生命周期轉(zhuǎn)換媳维。
6.3 模式:repository
- 客戶需要一種有效的方式來(lái)獲取對(duì)已存在的領(lǐng)域?qū)ο蟮囊谩H绻A(chǔ)設(shè)施提供了這方面的便利遏暴,那么開(kāi)發(fā)人員可能會(huì)增加很多可遍歷的關(guān)聯(lián)侄刽,這會(huì)使模型變得非常混亂朋凉。另一方面州丹,開(kāi)發(fā)人員可能使用查詢從數(shù)據(jù)庫(kù)中提取他們所需的數(shù)據(jù),或是直接提取具體的對(duì)象杂彭,而不是通過(guò)AGGREGATE的根來(lái)得到這些對(duì)象墓毒。這樣就導(dǎo)致領(lǐng)域邏輯進(jìn)入查詢和客戶代碼中,而ENTITY和VALUE OBJECT則變成單純的數(shù)據(jù)容器亲怠。采用大多數(shù)處理數(shù)據(jù)庫(kù)訪問(wèn)的技術(shù)復(fù)雜性很快就會(huì)使客戶代碼變得混亂所计,這將導(dǎo)致開(kāi)發(fā)人員簡(jiǎn)化領(lǐng)域?qū)樱罱K使模型變得無(wú)關(guān)緊要团秽。
- 除了通過(guò)根來(lái)遍歷查找對(duì)象這種方法外主胧,禁止其他方法對(duì)于聚合內(nèi)部的任何對(duì)象進(jìn)行訪問(wèn)
- 為每種需要全局訪問(wèn)的對(duì)象創(chuàng)建這個(gè)對(duì)象,這個(gè)對(duì)象相當(dāng)于該類型的所有對(duì)象在內(nèi)存中的這一個(gè)集合的替身习勤,通過(guò)這個(gè)眾所周知的全局接口來(lái)提供訪問(wèn)踪栋。提供添加和刪除對(duì)象的方法,用這些方法來(lái)封裝在數(shù)據(jù)存儲(chǔ)中實(shí)際插入或者刪除的操作图毕。提供根據(jù)具體條件來(lái)挑選對(duì)象的方法夷都,并返回屬性值滿足查詢條件的對(duì)象或者對(duì)象集合,從而將實(shí)際的存儲(chǔ)和查詢技術(shù)封裝起來(lái)予颤。只為那些確實(shí)需要直接訪問(wèn)的aggregate根提供repository囤官。讓客戶始終聚焦于模型,而將所有對(duì)象的存儲(chǔ)和訪問(wèn)操作交給repository蛤虐。
6.3.1 repository 查詢
- 返回某些類型的匯總計(jì)算也符合repository 的概念
- 基于specification 的查詢是一種優(yōu)雅和靈活的查詢方式
6.3.2 開(kāi)發(fā)人員不能忽略的repository的實(shí)現(xiàn)
6.3.3 repository 實(shí)現(xiàn)
- repository概念在很多情況下都使用治拿。可能實(shí)現(xiàn)方法有很多了笆焰,這里只能列出如下一些需要謹(jǐn)記的注意事項(xiàng):
- 對(duì)類型進(jìn)行抽象
- 充分利用與客戶解耦的優(yōu)點(diǎn)
- 將事務(wù)的控制權(quán)交給客戶
6.3.4 在框架內(nèi)工作
- 持久化框架的選擇
6.3.5 repository 和factory 的關(guān)系
- Factory 負(fù)責(zé)處理對(duì)象的生命周期的開(kāi)始,repository 幫助管理生命周期的中間和結(jié)束
-
repository可以委托factory來(lái)創(chuàng)建一個(gè)對(duì)象见坑。
-
客戶使用repository存儲(chǔ)新對(duì)象
6.4 為關(guān)系數(shù)據(jù)庫(kù)設(shè)計(jì)對(duì)象
第七章 使用語(yǔ)言:一個(gè)擴(kuò)展的示例
7.1 貨物運(yùn)輸系統(tǒng)簡(jiǎn)介
7.2 隔離領(lǐng)域:引入應(yīng)用層
- 為了防止領(lǐng)域的職責(zé)與系統(tǒng)的其他部分混雜在一起嚷掠,我們應(yīng)用layered architecture 把領(lǐng)域?qū)觿澐殖鰜?lái)。
- 三個(gè)功能分配給三個(gè)應(yīng)用層類荞驴,應(yīng)用層類是協(xié)調(diào)者
- 跟蹤查詢
- 預(yù)定應(yīng)用
- 事件日志應(yīng)用
7.3 將entity 和 value object 區(qū)別開(kāi)
- 領(lǐng)域?qū)ο蠓诸?/li>
- Customer :entity
- Cargo:entity
- HandlingEvent and Carrier Movement:entity
- Location:entity
- Delivery History:entity
- Delivery Specification:value object
- Role 和其他屬性
7.4 設(shè)計(jì)運(yùn)輸領(lǐng)域中的關(guān)聯(lián)
7.5 Aggregate邊界
7.6 選擇repository
-
在我們的設(shè)計(jì)中不皆,有5個(gè)實(shí)體是aggreagte的根,因此在選擇存儲(chǔ)時(shí)只需要考慮這5個(gè)實(shí)體熊楼,因?yàn)槠渌麑?shí)體都不能有repotitory霹娄。
7.7 場(chǎng)景走查
- 為了復(fù)核這些決策,我們需要經(jīng)常走查場(chǎng)景,以確保能夠有效的解決應(yīng)用問(wèn)題
7.7.1 應(yīng)用程序特性舉例:更新cargo的目的地
7.7.2 應(yīng)用程序特性舉例:重復(fù)業(yè)務(wù)
7.8 對(duì)象的創(chuàng)建
7.8.1 Cargo的factory和構(gòu)造函數(shù)
7.8.2 添加handing event
7.9 停一下犬耻,重構(gòu):Cargo Aggregate的另一種設(shè)計(jì)
7.10 運(yùn)輸模型中的module
7.11 引入新特性:配額檢查
7.11.1 連接兩個(gè)系統(tǒng)
銷售管理系統(tǒng)并不是這里所使用的模型編寫(xiě)的踩晶,如果book application 與它直接交互,那應(yīng)用程序必須適應(yīng)另一個(gè)系統(tǒng)的設(shè)計(jì)枕磁,這將很難保持一個(gè)清晰的module driven design渡蜻,而且會(huì)混淆ubiquitous language。相反我們創(chuàng)建一個(gè)類计济,讓它充當(dāng)我們和銷售管理系統(tǒng)之間的翻譯茸苇。但它不是一種通用機(jī)制,只是對(duì)我們應(yīng)用所需要的特性進(jìn)行翻譯沦寂,并根據(jù)我們的領(lǐng)域模型重新對(duì)這些特性進(jìn)行抽象学密。這個(gè)類將作為一個(gè)anticorruption layer
應(yīng)該使用更有價(jià)值的語(yǔ)言來(lái)重新描述問(wèn)題
7.11.2 進(jìn)一步完善模型:劃分業(yè)務(wù)
重新抽象系統(tǒng)系統(tǒng)領(lǐng)域:我們需要增加貨物類別的知識(shí),以便使模型更加豐富传藏。而且需要與領(lǐng)域?qū)<乙黄疬M(jìn)行頭腦風(fēng)暴活動(dòng)腻暮,以便于抽象出新的概念。
-
Enterprise Segement:企業(yè)部門單元
Allcation Checker 將充當(dāng)Enterprise Segment 與外部系統(tǒng)類別名稱之間的翻譯漩氨。Cargo Repository還必須提供一種基于Enterprise Segement的查詢西壮。
-
發(fā)現(xiàn)問(wèn)題
7.11.3 性能優(yōu)化
7.12 小結(jié)
第三部分 通過(guò)重構(gòu)加深理解
- 當(dāng)然我們面臨真正的挑戰(zhàn)是找到深層次的模型,這個(gè)模型不僅能捕捉到領(lǐng)域?qū)<业奈⒚铌P(guān)注點(diǎn)叫惊,還可以驅(qū)動(dòng)切實(shí)可行的驅(qū)動(dòng)設(shè)計(jì)款青。
- 要想成功的開(kāi)發(fā)出實(shí)用的模型,需要注意以下三點(diǎn):
- 復(fù)雜巧妙的領(lǐng)域模型是可以實(shí)現(xiàn)的霍狰,也值得我們?nèi)セㄙM(fèi)力氣實(shí)現(xiàn)的
- 這樣的模型離開(kāi)不斷的重構(gòu)是很難開(kāi)發(fā)出來(lái)的抡草,重構(gòu)需要領(lǐng)域?qū)<液蜔釔?ài)學(xué)習(xí)領(lǐng)域知識(shí)的開(kāi)發(fā)人員密切參與進(jìn)來(lái)的
- 要實(shí)現(xiàn)并有效的運(yùn)用模型,需要精通設(shè)計(jì)技巧
深層領(lǐng)域模型能夠穿越領(lǐng)域表象蔗坯,清晰的表達(dá)出專家們的主要關(guān)注點(diǎn)以及最相關(guān)的知識(shí)康震。
恰當(dāng)反應(yīng)領(lǐng)域的模型通常都具有功能多樣性、簡(jiǎn)單易用和解釋力強(qiáng)的特性
第8章 突破
8.1 一個(gè)關(guān)于突破的故事
8.1.1 華而不實(shí)的模型
8.1.2 突破
- loan 股份和facility 的股份可以在互不影響的情況下獨(dú)立發(fā)生變化
- 需求發(fā)生變化宾濒,具體參考P134 內(nèi)容
8.1.3 更深層模型
-
股份抽象模型
-
使用share pie的loan 模型
8.1.4 冷靜決策
- 最后銀團(tuán)貸款項(xiàng)目進(jìn)行了重構(gòu)
8.1.5 成果
8.2 機(jī)遇
- 當(dāng)突破帶來(lái)深層次模型時(shí)腿短,通常會(huì)讓人感到不安。與大部分重構(gòu)相比绘梦,這種變化的回報(bào)更多橘忱,風(fēng)險(xiǎn)也更高。而且突破出現(xiàn)的時(shí)機(jī)可能不合時(shí)宜卸奉。
8.3 關(guān)注根本
- 不要試圖制造突破钝诚,那只會(huì)使項(xiàng)目陷入困境。通常榄棵,只有實(shí)現(xiàn)許多適度的重構(gòu)才有可能出現(xiàn)突破凝颇。在大部分的時(shí)間里潘拱,我們都在進(jìn)行微小的改進(jìn)。而在這種持續(xù)改進(jìn)中深層次模型含義也逐漸顯現(xiàn)拧略。
- 要為突破做準(zhǔn)備芦岂,應(yīng)專注于知識(shí)消化過(guò)程,同時(shí)也要逐漸建立健壯的ubiquitous language辑鲤。尋找那些重要的領(lǐng)域概念盔腔,并在模型中清晰地表達(dá)出來(lái)。精化模型月褥,使其更具有柔性弛随。提煉模型。利用這些更容易掌握的手段使模型變得更清晰宁赤,這通常會(huì)帶來(lái)突破舀透。
8.4 后記:越來(lái)越多的新理解
第9章 將隱式概念轉(zhuǎn)換為顯示概念
- 若開(kāi)發(fā)人員識(shí)別出設(shè)計(jì)中隱含的某個(gè)概念或者討論中受到啟發(fā)而發(fā)現(xiàn)一個(gè)概念時(shí),就會(huì)對(duì)領(lǐng)域模型和相應(yīng)的代碼進(jìn)行許多轉(zhuǎn)換决左,在模型中添加一個(gè)或多個(gè)對(duì)象和關(guān)系時(shí)愕够,從而將此概念顯示的表達(dá)出來(lái)
9.1 概念挖掘
9.1.1 傾聽(tīng)語(yǔ)言
- 傾聽(tīng)領(lǐng)域?qū)<沂褂玫恼Z(yǔ)言。有沒(méi)有一些術(shù)語(yǔ)能夠簡(jiǎn)潔的表達(dá)出復(fù)雜的概念佛猛?他們有沒(méi)有糾正過(guò)你的用詞惑芭?當(dāng)你使用某些特定詞語(yǔ)的時(shí)候,他們臉上是否已經(jīng)不再流露出迷惑的表情继找?這些都暗示了某個(gè)概念可以改進(jìn)模型遂跟。
-
運(yùn)輸模型
9.1.2 檢查不足之處
-
利息模型
-
重構(gòu)后的深層模型
-
更深層次模型
-
重構(gòu)后的深層模型
9.1.3 思考矛盾之處
9.1.4 查閱書(shū)籍
9.1.5 嘗試、再嘗試
9.2 如何為那些不太明顯的概念建模
9.2.1 顯示的約束
- 約束是模型概念中非常重要的類別婴渡。它們通常是隱含的幻锁,將它們顯示的表現(xiàn)出來(lái)可以極大的提高設(shè)計(jì)質(zhì)量
9.2.2 將過(guò)程建模為領(lǐng)域?qū)ο?/h3>
- 我們討論的是存在領(lǐng)域中的過(guò)程,我們必須在模型中把這些過(guò)程表示出來(lái)边臼。否則當(dāng)這些過(guò)程顯露出來(lái)時(shí)哄尔,往往會(huì)使對(duì)象設(shè)計(jì)變得笨拙
9.2.3 模式:specification
9.2.4 specification的應(yīng)用和實(shí)現(xiàn)
- specification最有價(jià)值的地方在于他可以將不同的應(yīng)用功能統(tǒng)一起來(lái)。出于以下三個(gè)目的中的一個(gè)或者多個(gè)柠并,我們需要指定對(duì)象的狀態(tài)
- 驗(yàn)證對(duì)象岭接,檢查它是否滿足某些需求或者已經(jīng)為實(shí)現(xiàn)某個(gè)目標(biāo)做好了準(zhǔn)備。
- 從集合中選擇一個(gè)對(duì)象
- 指定在創(chuàng)建對(duì)象時(shí)必須滿足某種需求
第10章 柔性設(shè)計(jì)
- 為了使項(xiàng)目能夠隨著開(kāi)發(fā)工作的進(jìn)行加速前進(jìn)臼予,而 不會(huì)由于它自己的老化停滯不前亿傅,設(shè)計(jì)必須讓人們樂(lè)于使用,而且易于做出修改瘟栖。這就是柔性設(shè)計(jì)(supple design)。
- 柔性設(shè)計(jì)是對(duì)深層模型的補(bǔ)充
10.1 模式:intention-revealing interfaces
-
前一章節(jié)深入探討了對(duì)于規(guī)則和計(jì)算進(jìn)行顯示的建模谅阿,實(shí)現(xiàn)這樣的對(duì)象要求我們深入理解計(jì)算或者規(guī)則的大部分細(xì)節(jié)半哟。對(duì)象的強(qiáng)大功能就是把細(xì)節(jié)隱藏起來(lái)酬滤,如此一來(lái),客戶代碼就能很簡(jiǎn)單寓涨,而且可以用高層概念來(lái)解釋盯串。
2.一些有助于獲得柔性設(shè)計(jì)的模式
Kent Beck 曾經(jīng)提出通過(guò)intention - revealing selector (釋意命名選擇器)來(lái)選擇方法的名稱,使名稱表達(dá)其目的戒良。類型名稱体捏、方法名稱和參數(shù)名稱組合在一起,共同形成了一個(gè)intention-revealing interface糯崎。
在命名類和操作時(shí)几缭,要描述他們的效果和目的,而不是表達(dá)他們是通過(guò)何種方式達(dá)到目的的沃呢。這樣可以使用客戶開(kāi)發(fā)人員不必去理解內(nèi)部細(xì)節(jié)年栓。這些名稱應(yīng)該與ubiquitous language 保持一致,便于團(tuán)隊(duì)人員可以迅速推斷出他們的意義薄霜。在創(chuàng)建一個(gè)行為前為它編寫(xiě)一個(gè)測(cè)試某抓,這樣可以站在客戶開(kāi)發(fā)人員的角度思考他們。
10.2 模式:side-effect-free function
- 任何對(duì)未來(lái)操作產(chǎn)生影響的系統(tǒng)狀態(tài)改變都可以稱為副作用
- 多個(gè)規(guī)則的相互作用或者計(jì)算的組合產(chǎn)生的結(jié)果是很預(yù)測(cè)的惰瓜。開(kāi)發(fā)人員在調(diào)用一個(gè)操作時(shí)否副,為了預(yù)測(cè)操作的結(jié)果,必須理解它的實(shí)現(xiàn)以及它所調(diào)用其它方法的實(shí)現(xiàn)崎坊。如果不得不“揭開(kāi)接口的面紗”备禀,那么接口的抽象作用就受到了限制。如果沒(méi)有了可以安全的預(yù)見(jiàn)結(jié)果的抽象流强,開(kāi)發(fā)人員就必須限制“組合爆炸”痹届,這就限制了系統(tǒng)行為的豐富性。
- 返回結(jié)果而不產(chǎn)生副作用的操作稱之為“函數(shù)”打月。
- 把命令和查詢嚴(yán)格的放在不同的模型中队腐。確保導(dǎo)致?tīng)顟B(tài)改變的方法不返回領(lǐng)域數(shù)據(jù),并盡可能的保持簡(jiǎn)單奏篙。在不引起任何副作用的方法中執(zhí)行所有查詢和計(jì)算柴淘。
5.總有一些替代的模型和設(shè)計(jì),他們不要求對(duì)現(xiàn)有版本進(jìn)行任何修改秘通。相反为严,他們創(chuàng)建并返回一個(gè)value object用于表示計(jì)算結(jié)果
- 盡可能的把程序的邏輯放在函數(shù)中,因而函數(shù)是只產(chǎn)生結(jié)果而不會(huì)產(chǎn)生副作用的操作肺稀。嚴(yán)格的把命令隔離到不返回領(lǐng)域信息的第股,非常簡(jiǎn)單的操作中。當(dāng)發(fā)現(xiàn)一個(gè)非常適合承擔(dān)復(fù)雜邏輯的概念時(shí)话原,就把復(fù)雜的邏輯轉(zhuǎn)移到value object中夕吻,這樣就可以進(jìn)一步的控制副作用诲锹。
10.3 模式:assertion
- 契約式設(shè)計(jì),向前推進(jìn)了一小步涉馅。通過(guò)給出類和方法 的斷言使開(kāi)發(fā)人員知道了肯定發(fā)生的結(jié)果归园。簡(jiǎn)而言之,后置條件描述了一個(gè)操作的副作用稚矿,也就是調(diào)用一個(gè)方法之后必然發(fā)生的結(jié)果庸诱。前置條件就像是合同條款,即為了滿足后置條件而必須要滿足的前置條件晤揣。類的固定規(guī)則規(guī)定了在操作結(jié)束時(shí)對(duì)象的狀態(tài)桥爽。也可以將aggregate作為一個(gè)整體來(lái)為它聲明規(guī)定規(guī)則,這些都是嚴(yán)格定義的完整性規(guī)則碉渡。
- 把操作的后置條件和類以及aggregate的固定規(guī)則表達(dá)清楚聚谁。如果在你的編程語(yǔ)言中不能直接編寫(xiě)斷言,那么就把它寫(xiě)成自動(dòng)的單元測(cè)試滞诺。還可以把它寫(xiě)在文檔和圖中形导。
10.4 模式:conceptual contour
- conceptual contour:概念輪廓
- 把設(shè)計(jì)元素(操作,接口习霹,類以及aggregate)分解為內(nèi)聚的單元朵耕,在過(guò)程中,你對(duì)于領(lǐng)域中一切重要的劃分的直觀認(rèn)知也需要考慮在內(nèi)淋叶。在連續(xù)的重構(gòu)中觀察發(fā)生的變化和保證穩(wěn)定的規(guī)律性阎曹,并尋找能夠解釋這些變化模式的底層conceptual contour。使模型與領(lǐng)域中那些一致的方面相匹配煞檩。
10.5 模式:standalone class
- module和aggregate 目的是為了限制互相依賴的關(guān)系網(wǎng)处嫌。
- 低耦合是對(duì)象設(shè)計(jì)的一個(gè)基本要素。盡一切可能保持低耦合斟湃,把其它所有無(wú)關(guān)概念提取到對(duì)象之外熏迹。這樣類就變得完全獨(dú)立了,這就可以使我們單獨(dú)研究和理解他們凝赛。每個(gè)這樣獨(dú)立類都極大的減輕因理解module而帶來(lái)的負(fù)擔(dān)注暗。
10.6 模式:closure of operation (閉合操作)
- 在適當(dāng)?shù)那樾蜗拢诙x操作時(shí)墓猎,讓它的參數(shù)類型與返回類型保持一致捆昏。如果實(shí)現(xiàn)者的狀態(tài)在計(jì)算中會(huì)用到,那么實(shí)現(xiàn)者實(shí)際上就是操作的一個(gè)參數(shù)毙沾。因此參數(shù)和返回值應(yīng)該與實(shí)現(xiàn)者有相同的類型骗卜。這樣的操作就是在該類型的實(shí)例集合中的閉合操作。閉合操作提供了一個(gè)高層接口,同時(shí)又不會(huì)引入其他概念的任何依賴寇仓。
10.7 聲明式設(shè)計(jì)
10.8 聲明式設(shè)計(jì)風(fēng)格
10.9 切入問(wèn)題的角度
10.9.1 分割子領(lǐng)域
10.9.2 盡可能利用已有的形式
第11章 應(yīng)用分析模式
- 分析模式是一種概念集合勇皇,用來(lái)表示業(yè)務(wù)建模中的常見(jiàn)結(jié)構(gòu)。它可能只與一個(gè)領(lǐng)域有關(guān)焚刺,也可能跨域多個(gè)領(lǐng)域。
第12章:將設(shè)計(jì)模式應(yīng)用于模型
12.1 模式:strategy
12.2 模式:composite
12.3 為什么沒(méi)有介紹flyweight
第13章 通過(guò)重構(gòu)得到更深次的理解
- 有三件事情是必須要關(guān)注的:
- 以領(lǐng)域?yàn)楸?/li>
- 用一種不同的方式看待事物
- 始終堅(jiān)持與領(lǐng)域?qū)<覍?duì)話
13.1 開(kāi)始重構(gòu)
13.2 探索團(tuán)隊(duì)
13.3 借鑒先前經(jīng)驗(yàn)
13.4 針對(duì)開(kāi)發(fā)人員的設(shè)計(jì)
13.5 重構(gòu)的時(shí)機(jī)
13.6 危機(jī)就是機(jī)遇
第四部分 戰(zhàn)略設(shè)計(jì)
- 三大主題:上下文门烂、精煉和大型結(jié)構(gòu)
第14章 保持模型的完整性
- 大型系統(tǒng)領(lǐng)域模型的完全統(tǒng)一即不可行乳愉,也不劃算
- 既然無(wú)法維護(hù)一個(gè)涵蓋整個(gè)企業(yè)的統(tǒng)一模型,那就不要再受到這種思路的限制屯远。通過(guò)預(yù)先決定什么應(yīng)該統(tǒng)一蔓姚,并實(shí)際認(rèn)識(shí)到什么不能統(tǒng)一,我們就能創(chuàng)建一個(gè)清晰的,共同的視圖
- 我們需要使用一種方式來(lái)標(biāo)記出來(lái)不同模型之間的邊界和關(guān)系。
- bounded context(限界上下文)定義了每個(gè)模型的應(yīng)用范圍割笙,而context map(上下文圖)則給出來(lái)項(xiàng)目上下文以及他們之間的關(guān)系的總體視圖蒙畴。
- 在這個(gè)穩(wěn)定的基礎(chǔ)上,我們就可以開(kāi)始實(shí)施那些在界定和關(guān)聯(lián)context方面更有效的策略了-從通過(guò)共享內(nèi)核來(lái)緊密關(guān)聯(lián)上下文蝇棉,到那些各行其道
14.1 模型:bounded context
- 任何大型項(xiàng)目都會(huì)存在多個(gè)模型。而當(dāng)基于不同模型的代碼被組合在一起后,軟件就會(huì)出現(xiàn)bug恬砂、變得不可靠和難以理解。團(tuán)隊(duì)成員之間的溝通變的混亂蓬痒。人們往往弄不清楚一個(gè)模型不應(yīng)該在哪個(gè)上下文中使用
- 一個(gè)模型只在一個(gè)上下文使用泻骤。
- 明確定義模型所應(yīng)用的上下文。根據(jù)團(tuán)隊(duì)的組織梧奢,軟件系統(tǒng)的各個(gè)部分的用法以及物理表現(xiàn)(代碼以及數(shù)據(jù)庫(kù)模型等)來(lái)設(shè)置模型的邊界狱掂。在這些邊界中嚴(yán)格保持模型的一致性,而不要受到邊界之外問(wèn)題的干擾和混亂亲轨。
- bounded context不是module
- 將不同模型的元素組合在一起可能會(huì)引發(fā)兩類問(wèn)題:重復(fù)的概念和假同源趋惨。重復(fù)的概念指的是兩個(gè)模型元素實(shí)際上表示同一個(gè)概念。假同源指的是使用相同屬于的兩個(gè)人認(rèn)為是在討論同一件事瓶埋,但是實(shí)際上不是這樣的希柿。
14.2 模式:continuous integration
- 當(dāng)很多人在同一個(gè)bounded context中工作時(shí),模型很容易發(fā)生分裂养筒。如果將系統(tǒng)分解為更小的context曾撤,最終又難以保持集成度和一致性。
- continuous integration是指把一個(gè)上下文中的所有工作足夠頻繁的合并到一起晕粪,并使他們保持一致挤悉,以便當(dāng)模型發(fā)生分裂時(shí),可以迅速發(fā)現(xiàn)并糾正問(wèn)題巫湘。
- 團(tuán)隊(duì)成員之間通過(guò)經(jīng)常溝通來(lái)保證概念的集成装悲。團(tuán)隊(duì)成員必須對(duì)不斷變化的模型形成一個(gè)共同的理解昏鹃。
- 建立一個(gè)把所有代碼和其他實(shí)現(xiàn)工件頻繁的合并到一起的工程,并通過(guò)自動(dòng)化測(cè)試來(lái)快速查明模型的分類問(wèn)題诀诊。嚴(yán)格堅(jiān)持使用ubiquitous lanuage洞渤,以便在不同人的頭腦中演變出不同的概念時(shí),使所有人對(duì)模型達(dá)成一個(gè)共識(shí)属瓣。
14.3 模式:context map
- 其他團(tuán)隊(duì)中的人員并不是十分清楚context的邊界载迄,他們會(huì)不知不覺(jué)中做出一些更改,從而是邊界變得模糊或者互聯(lián)變得復(fù)雜抡蛙。當(dāng)不同的上下文必須互相連接時(shí)护昧,他們可能會(huì)互相重疊。
- 通過(guò)定義不同的上下文之間的關(guān)系粗截,并在項(xiàng)目中創(chuàng)建一個(gè)所有上下文的全局視圖惋耙,可以減少混亂
- 識(shí)別在項(xiàng)目中起作用的每個(gè)模型,并定義其bounded context熊昌。這包括非面向?qū)ο笞酉到y(tǒng)的隱含模型绽榛。為每個(gè)bounded contetx命名。并把名稱添加到ubiquitous language中浴捆。描述模型之間的聯(lián)系點(diǎn)蒜田,明確所有通信需要的轉(zhuǎn)換,并突出任何共享的內(nèi)容选泻。先將當(dāng)前的情況描繪出來(lái)冲粤,以后再做改變。
14.3.1 測(cè)試context的邊界
- 對(duì)各個(gè)bounded context的聯(lián)系點(diǎn)的測(cè)試特別重要
14.3.2 context map的組織和文檔化
- 兩個(gè)重點(diǎn)
- bounded context應(yīng)該有名稱页眯,以便于可以討論他們梯捕。這些名稱應(yīng)該被添加到團(tuán)隊(duì)的ubiquitous language中
- 每個(gè)人都應(yīng)該知道邊界在哪里,而且應(yīng)該能夠分辨出任何代碼段的context窝撵,或者任何情況的context
- 一旦定義了counded context傀顾,那么把不同的上下文的代碼隔離到不同的module中就再自然不過(guò)濾。
- 我們可以用命名規(guī)范來(lái)表明這一點(diǎn)碌奉,后者使用其他簡(jiǎn)單且不會(huì)產(chǎn)生混淆的機(jī)制
14.4 bounded context之間的關(guān)系
14.5 模式:shared kernel
- 當(dāng)不同的團(tuán)隊(duì)開(kāi)發(fā)一些緊密相關(guān)的應(yīng)用程序時(shí)短曾,如果團(tuán)隊(duì)之間不進(jìn)行協(xié)調(diào),即使短時(shí)間內(nèi)能夠取得快速進(jìn)展赐劣,但他們開(kāi)發(fā)的產(chǎn)品可能無(wú)法結(jié)合到一起嫉拐。最后可能不得不耗費(fèi)大量精力在轉(zhuǎn)換層上,并且頻繁的進(jìn)行改動(dòng)魁兼,不如一開(kāi)始就使用continuous integration那么省心省力婉徘,同時(shí)這也造成重復(fù)工農(nóng)工作,并且無(wú)法使用公共的ubiquitous language所帶來(lái)的好處
- 從領(lǐng)域模型中選出兩個(gè)團(tuán)隊(duì)都統(tǒng)一共享的一個(gè)子集。當(dāng)然盖呼,除了這個(gè)模型子集以外儒鹿,還包括與該模型部分相關(guān)的代碼子集,或數(shù)據(jù)庫(kù)設(shè)計(jì)的子集几晤。這部分明確共享的內(nèi)容具有特殊的地位约炎,一個(gè)團(tuán)隊(duì)在沒(méi)有與另外一個(gè)團(tuán)隊(duì)上商量的情況下不應(yīng)該擅自修改它。
- 共享內(nèi)核中必須集成自動(dòng)測(cè)試套件蟹瘾,因?yàn)樾薷墓蚕韮?nèi)核時(shí)章钾,必須通過(guò)兩個(gè)團(tuán)隊(duì)的所有測(cè)試
- shared kernel 通常是core domain,或者是一組generic subdomain(通用子領(lǐng)域)热芹,也可能是二者兼有。
14.6 模式:customer/supplier development team
- 在兩個(gè)團(tuán)隊(duì)之間建立一種米孔雀的客戶/供應(yīng)商關(guān)系惨撇。在計(jì)劃會(huì)議中伊脓,下游團(tuán)隊(duì)相當(dāng)于上游團(tuán)隊(duì)的客戶。根據(jù)下游團(tuán)隊(duì)的需求來(lái)協(xié)商需要執(zhí)行的任務(wù)并為這些任務(wù)做預(yù)算魁衙,以便于每個(gè)人都知道雙方的約定和進(jìn)度
- 兩個(gè)團(tuán)隊(duì)共同開(kāi)發(fā)自動(dòng)化驗(yàn)收測(cè)試报腔,用于驗(yàn)證逾期的接口,把這些測(cè)試添加到上游團(tuán)隊(duì)的測(cè)試套件中剖淀,以便作為其持續(xù)集成的一部分來(lái)運(yùn)行纯蛾。這些測(cè)試使上游團(tuán)隊(duì)在做出修改時(shí),不比擔(dān)心對(duì)于上游團(tuán)隊(duì)產(chǎn)生副作用纵隔。
14.7 模式:conformist(跟隨者)
- 通過(guò)嚴(yán)格遵從上游團(tuán)隊(duì)的模型翻诉,可以消除在bounded context之間進(jìn)行轉(zhuǎn)換的復(fù)雜性。盡管這會(huì)限制下游設(shè)計(jì)人員的風(fēng)格捌刮,而且可能不會(huì)得到理想的應(yīng)用程序模型碰煌,單選擇conformity模式可以極大的簡(jiǎn)化集成。此外绅作,這樣還可以與供應(yīng)商團(tuán)隊(duì)共享ubiquitous language芦圾。供應(yīng)商處于統(tǒng)治地位,因此最好使溝通變?nèi)菀锥砣稀K麄儚睦髁x的角度出發(fā)个少,會(huì)與你分享信息
14.8 模式:anticorruption layer
AGGREGATE就是一組相關(guān)對(duì)象的集合,我們把它作為數(shù)據(jù)修改的單元辛馆。每個(gè)AGGREGATE
都有一個(gè)根(root)和一個(gè)邊界(boundary)俺陋。邊界定義了AGGREGATE的內(nèi)部都有什么。根則是AGGREGATE所包含的一個(gè)特定ENTITY昙篙。對(duì)AGGREGATE而言腊状,外部對(duì)象只可以引用根,而邊界內(nèi)部的對(duì)象之間則可以互相引用苔可。除根以外的其他ENTITY都有本地標(biāo)識(shí)寿酌,但這些標(biāo)識(shí)只在AGGREGATE內(nèi)部才需要加以區(qū)別,因?yàn)橥獠繉?duì)象除了根ENTITY之外看不到其他對(duì)象硕蛹。
每個(gè)aggregate都有一個(gè)根和邊界。邊界定義了aggregate的內(nèi)部都有什么硕并,根則是aggregate所包含的一個(gè)特定實(shí)體法焰。對(duì)aggregate而言,外部只能引入根倔毙,而邊界內(nèi)部的對(duì)象之間可以互相引用埃仪。
固定規(guī)則是指在數(shù)據(jù)變化式必須保持一致性規(guī)則,其涉及aggregate之間的內(nèi)部關(guān)系陕赃。而任何跨越aggregate的規(guī)則將不要求每時(shí)每刻都保持最新的狀態(tài)卵蛉。通過(guò)事件處理、批處理或者其他更新機(jī)制么库,這些依賴會(huì)在一定時(shí)間內(nèi)得以解決傻丝。為了實(shí)現(xiàn)概念上的aggregate,需要對(duì)所有的事務(wù)應(yīng)用一組規(guī)則:
- 根entity 具有全局意識(shí)诉儒,它最終負(fù)責(zé)檢查固定規(guī)則
- 邊界內(nèi)entity 具有本地標(biāo)識(shí)葡缰,這些標(biāo)識(shí)在本地內(nèi)部是唯一的
- aggregate外部的對(duì)象不能引用除entity 之外的任何內(nèi)部對(duì)象。
- 只有aggregte的根才能直接通過(guò)數(shù)據(jù)庫(kù)查詢獲取,所有其他的對(duì)象必須通過(guò)遍歷關(guān)聯(lián)獲取泛释。
- aggregate內(nèi)部的對(duì)象可以保持對(duì)其他aggregate的引用
- 刪除操作必須一次刪除aggregate邊界之內(nèi)的所有對(duì)象
- 當(dāng)提交對(duì)aggregate邊界內(nèi)部的任何修改時(shí)滤愕,整個(gè)aggregate所有的固定規(guī)則必須滿足
我們應(yīng)該將entity和value object分門別類的聚集到aggregate中,并定義每個(gè)aggregate的邊界怜校,在每個(gè)aggregate中间影,選擇一個(gè)entity作為根,并通過(guò)根來(lái)控制對(duì)邊界內(nèi)其他對(duì)象的所有訪問(wèn)茄茁。只允許外部對(duì)象保持對(duì)根的引用魂贬。對(duì)內(nèi)部成員的臨時(shí)引用可以被傳遞出去,但僅在一次操作中有效胰丁。由于根控制訪問(wèn)随橘,因此不能繞過(guò)它來(lái)修改內(nèi)部對(duì)象。這種設(shè)計(jì)有利于確保aggregate中的對(duì)象滿足所有固定規(guī)則锦庸,也可以確保在任何狀態(tài)變化時(shí)aggreaget作為一個(gè)整體滿足固定規(guī)則机蔗。
- 用于重建對(duì)象的entity factory不分配新的跟蹤id
- 當(dāng)固定規(guī)則未被滿足時(shí)魔眨,重建對(duì)象的factory采用不同的方式進(jìn)行處理
repository可以委托factory來(lái)創(chuàng)建一個(gè)對(duì)象见坑。
客戶使用repository存儲(chǔ)新對(duì)象
在我們的設(shè)計(jì)中不皆,有5個(gè)實(shí)體是aggreagte的根,因此在選擇存儲(chǔ)時(shí)只需要考慮這5個(gè)實(shí)體熊楼,因?yàn)槠渌麑?shí)體都不能有repotitory霹娄。
銷售管理系統(tǒng)并不是這里所使用的模型編寫(xiě)的踩晶,如果book application 與它直接交互,那應(yīng)用程序必須適應(yīng)另一個(gè)系統(tǒng)的設(shè)計(jì)枕磁,這將很難保持一個(gè)清晰的module driven design渡蜻,而且會(huì)混淆ubiquitous language。相反我們創(chuàng)建一個(gè)類计济,讓它充當(dāng)我們和銷售管理系統(tǒng)之間的翻譯茸苇。但它不是一種通用機(jī)制,只是對(duì)我們應(yīng)用所需要的特性進(jìn)行翻譯沦寂,并根據(jù)我們的領(lǐng)域模型重新對(duì)這些特性進(jìn)行抽象学密。這個(gè)類將作為一個(gè)anticorruption layer
應(yīng)該使用更有價(jià)值的語(yǔ)言來(lái)重新描述問(wèn)題
重新抽象系統(tǒng)系統(tǒng)領(lǐng)域:我們需要增加貨物類別的知識(shí),以便使模型更加豐富传藏。而且需要與領(lǐng)域?qū)<乙黄疬M(jìn)行頭腦風(fēng)暴活動(dòng)腻暮,以便于抽象出新的概念。
Enterprise Segement:企業(yè)部門單元
Allcation Checker 將充當(dāng)Enterprise Segment 與外部系統(tǒng)類別名稱之間的翻譯漩氨。Cargo Repository還必須提供一種基于Enterprise Segement的查詢西壮。
發(fā)現(xiàn)問(wèn)題
深層領(lǐng)域模型能夠穿越領(lǐng)域表象蔗坯,清晰的表達(dá)出專家們的主要關(guān)注點(diǎn)以及最相關(guān)的知識(shí)康震。
恰當(dāng)反應(yīng)領(lǐng)域的模型通常都具有功能多樣性、簡(jiǎn)單易用和解釋力強(qiáng)的特性
股份抽象模型
使用share pie的loan 模型
運(yùn)輸模型
利息模型
重構(gòu)后的深層模型
更深層次模型
重構(gòu)后的深層模型
- 我們討論的是存在領(lǐng)域中的過(guò)程,我們必須在模型中把這些過(guò)程表示出來(lái)边臼。否則當(dāng)這些過(guò)程顯露出來(lái)時(shí)哄尔,往往會(huì)使對(duì)象設(shè)計(jì)變得笨拙
9.2.3 模式:specification
9.2.4 specification的應(yīng)用和實(shí)現(xiàn)
- specification最有價(jià)值的地方在于他可以將不同的應(yīng)用功能統(tǒng)一起來(lái)。出于以下三個(gè)目的中的一個(gè)或者多個(gè)柠并,我們需要指定對(duì)象的狀態(tài)
- 驗(yàn)證對(duì)象岭接,檢查它是否滿足某些需求或者已經(jīng)為實(shí)現(xiàn)某個(gè)目標(biāo)做好了準(zhǔn)備。
- 從集合中選擇一個(gè)對(duì)象
- 指定在創(chuàng)建對(duì)象時(shí)必須滿足某種需求
第10章 柔性設(shè)計(jì)
- 為了使項(xiàng)目能夠隨著開(kāi)發(fā)工作的進(jìn)行加速前進(jìn)臼予,而 不會(huì)由于它自己的老化停滯不前亿傅,設(shè)計(jì)必須讓人們樂(lè)于使用,而且易于做出修改瘟栖。這就是柔性設(shè)計(jì)(supple design)。
- 柔性設(shè)計(jì)是對(duì)深層模型的補(bǔ)充
10.1 模式:intention-revealing interfaces
-
前一章節(jié)深入探討了對(duì)于規(guī)則和計(jì)算進(jìn)行顯示的建模谅阿,實(shí)現(xiàn)這樣的對(duì)象要求我們深入理解計(jì)算或者規(guī)則的大部分細(xì)節(jié)半哟。對(duì)象的強(qiáng)大功能就是把細(xì)節(jié)隱藏起來(lái)酬滤,如此一來(lái),客戶代碼就能很簡(jiǎn)單寓涨,而且可以用高層概念來(lái)解釋盯串。
2.一些有助于獲得柔性設(shè)計(jì)的模式
Kent Beck 曾經(jīng)提出通過(guò)intention - revealing selector (釋意命名選擇器)來(lái)選擇方法的名稱,使名稱表達(dá)其目的戒良。類型名稱体捏、方法名稱和參數(shù)名稱組合在一起,共同形成了一個(gè)intention-revealing interface糯崎。
在命名類和操作時(shí)几缭,要描述他們的效果和目的,而不是表達(dá)他們是通過(guò)何種方式達(dá)到目的的沃呢。這樣可以使用客戶開(kāi)發(fā)人員不必去理解內(nèi)部細(xì)節(jié)年栓。這些名稱應(yīng)該與ubiquitous language 保持一致,便于團(tuán)隊(duì)人員可以迅速推斷出他們的意義薄霜。在創(chuàng)建一個(gè)行為前為它編寫(xiě)一個(gè)測(cè)試某抓,這樣可以站在客戶開(kāi)發(fā)人員的角度思考他們。
10.2 模式:side-effect-free function
- 任何對(duì)未來(lái)操作產(chǎn)生影響的系統(tǒng)狀態(tài)改變都可以稱為副作用
- 多個(gè)規(guī)則的相互作用或者計(jì)算的組合產(chǎn)生的結(jié)果是很預(yù)測(cè)的惰瓜。開(kāi)發(fā)人員在調(diào)用一個(gè)操作時(shí)否副,為了預(yù)測(cè)操作的結(jié)果,必須理解它的實(shí)現(xiàn)以及它所調(diào)用其它方法的實(shí)現(xiàn)崎坊。如果不得不“揭開(kāi)接口的面紗”备禀,那么接口的抽象作用就受到了限制。如果沒(méi)有了可以安全的預(yù)見(jiàn)結(jié)果的抽象流强,開(kāi)發(fā)人員就必須限制“組合爆炸”痹届,這就限制了系統(tǒng)行為的豐富性。
- 返回結(jié)果而不產(chǎn)生副作用的操作稱之為“函數(shù)”打月。
- 把命令和查詢嚴(yán)格的放在不同的模型中队腐。確保導(dǎo)致?tīng)顟B(tài)改變的方法不返回領(lǐng)域數(shù)據(jù),并盡可能的保持簡(jiǎn)單奏篙。在不引起任何副作用的方法中執(zhí)行所有查詢和計(jì)算柴淘。
5.總有一些替代的模型和設(shè)計(jì),他們不要求對(duì)現(xiàn)有版本進(jìn)行任何修改秘通。相反为严,他們創(chuàng)建并返回一個(gè)value object用于表示計(jì)算結(jié)果 - 盡可能的把程序的邏輯放在函數(shù)中,因而函數(shù)是只產(chǎn)生結(jié)果而不會(huì)產(chǎn)生副作用的操作肺稀。嚴(yán)格的把命令隔離到不返回領(lǐng)域信息的第股,非常簡(jiǎn)單的操作中。當(dāng)發(fā)現(xiàn)一個(gè)非常適合承擔(dān)復(fù)雜邏輯的概念時(shí)话原,就把復(fù)雜的邏輯轉(zhuǎn)移到value object中夕吻,這樣就可以進(jìn)一步的控制副作用诲锹。
10.3 模式:assertion
- 契約式設(shè)計(jì),向前推進(jìn)了一小步涉馅。通過(guò)給出類和方法 的斷言使開(kāi)發(fā)人員知道了肯定發(fā)生的結(jié)果归园。簡(jiǎn)而言之,后置條件描述了一個(gè)操作的副作用稚矿,也就是調(diào)用一個(gè)方法之后必然發(fā)生的結(jié)果庸诱。前置條件就像是合同條款,即為了滿足后置條件而必須要滿足的前置條件晤揣。類的固定規(guī)則規(guī)定了在操作結(jié)束時(shí)對(duì)象的狀態(tài)桥爽。也可以將aggregate作為一個(gè)整體來(lái)為它聲明規(guī)定規(guī)則,這些都是嚴(yán)格定義的完整性規(guī)則碉渡。
- 把操作的后置條件和類以及aggregate的固定規(guī)則表達(dá)清楚聚谁。如果在你的編程語(yǔ)言中不能直接編寫(xiě)斷言,那么就把它寫(xiě)成自動(dòng)的單元測(cè)試滞诺。還可以把它寫(xiě)在文檔和圖中形导。
10.4 模式:conceptual contour
- conceptual contour:概念輪廓
- 把設(shè)計(jì)元素(操作,接口习霹,類以及aggregate)分解為內(nèi)聚的單元朵耕,在過(guò)程中,你對(duì)于領(lǐng)域中一切重要的劃分的直觀認(rèn)知也需要考慮在內(nèi)淋叶。在連續(xù)的重構(gòu)中觀察發(fā)生的變化和保證穩(wěn)定的規(guī)律性阎曹,并尋找能夠解釋這些變化模式的底層conceptual contour。使模型與領(lǐng)域中那些一致的方面相匹配煞檩。
10.5 模式:standalone class
- module和aggregate 目的是為了限制互相依賴的關(guān)系網(wǎng)处嫌。
- 低耦合是對(duì)象設(shè)計(jì)的一個(gè)基本要素。盡一切可能保持低耦合斟湃,把其它所有無(wú)關(guān)概念提取到對(duì)象之外熏迹。這樣類就變得完全獨(dú)立了,這就可以使我們單獨(dú)研究和理解他們凝赛。每個(gè)這樣獨(dú)立類都極大的減輕因理解module而帶來(lái)的負(fù)擔(dān)注暗。
10.6 模式:closure of operation (閉合操作)
- 在適當(dāng)?shù)那樾蜗拢诙x操作時(shí)墓猎,讓它的參數(shù)類型與返回類型保持一致捆昏。如果實(shí)現(xiàn)者的狀態(tài)在計(jì)算中會(huì)用到,那么實(shí)現(xiàn)者實(shí)際上就是操作的一個(gè)參數(shù)毙沾。因此參數(shù)和返回值應(yīng)該與實(shí)現(xiàn)者有相同的類型骗卜。這樣的操作就是在該類型的實(shí)例集合中的閉合操作。閉合操作提供了一個(gè)高層接口,同時(shí)又不會(huì)引入其他概念的任何依賴寇仓。
10.7 聲明式設(shè)計(jì)
10.8 聲明式設(shè)計(jì)風(fēng)格
10.9 切入問(wèn)題的角度
10.9.1 分割子領(lǐng)域
10.9.2 盡可能利用已有的形式
第11章 應(yīng)用分析模式
- 分析模式是一種概念集合勇皇,用來(lái)表示業(yè)務(wù)建模中的常見(jiàn)結(jié)構(gòu)。它可能只與一個(gè)領(lǐng)域有關(guān)焚刺,也可能跨域多個(gè)領(lǐng)域。
第12章:將設(shè)計(jì)模式應(yīng)用于模型
12.1 模式:strategy
12.2 模式:composite
12.3 為什么沒(méi)有介紹flyweight
第13章 通過(guò)重構(gòu)得到更深次的理解
- 有三件事情是必須要關(guān)注的:
- 以領(lǐng)域?yàn)楸?/li>
- 用一種不同的方式看待事物
- 始終堅(jiān)持與領(lǐng)域?qū)<覍?duì)話
13.1 開(kāi)始重構(gòu)
13.2 探索團(tuán)隊(duì)
13.3 借鑒先前經(jīng)驗(yàn)
13.4 針對(duì)開(kāi)發(fā)人員的設(shè)計(jì)
13.5 重構(gòu)的時(shí)機(jī)
13.6 危機(jī)就是機(jī)遇
第四部分 戰(zhàn)略設(shè)計(jì)
- 三大主題:上下文门烂、精煉和大型結(jié)構(gòu)
第14章 保持模型的完整性
- 大型系統(tǒng)領(lǐng)域模型的完全統(tǒng)一即不可行乳愉,也不劃算
- 既然無(wú)法維護(hù)一個(gè)涵蓋整個(gè)企業(yè)的統(tǒng)一模型,那就不要再受到這種思路的限制屯远。通過(guò)預(yù)先決定什么應(yīng)該統(tǒng)一蔓姚,并實(shí)際認(rèn)識(shí)到什么不能統(tǒng)一,我們就能創(chuàng)建一個(gè)清晰的,共同的視圖
- 我們需要使用一種方式來(lái)標(biāo)記出來(lái)不同模型之間的邊界和關(guān)系。
- bounded context(限界上下文)定義了每個(gè)模型的應(yīng)用范圍割笙,而context map(上下文圖)則給出來(lái)項(xiàng)目上下文以及他們之間的關(guān)系的總體視圖蒙畴。
- 在這個(gè)穩(wěn)定的基礎(chǔ)上,我們就可以開(kāi)始實(shí)施那些在界定和關(guān)聯(lián)context方面更有效的策略了-從通過(guò)共享內(nèi)核來(lái)緊密關(guān)聯(lián)上下文蝇棉,到那些各行其道
14.1 模型:bounded context
- 任何大型項(xiàng)目都會(huì)存在多個(gè)模型。而當(dāng)基于不同模型的代碼被組合在一起后,軟件就會(huì)出現(xiàn)bug恬砂、變得不可靠和難以理解。團(tuán)隊(duì)成員之間的溝通變的混亂蓬痒。人們往往弄不清楚一個(gè)模型不應(yīng)該在哪個(gè)上下文中使用
- 一個(gè)模型只在一個(gè)上下文使用泻骤。
- 明確定義模型所應(yīng)用的上下文。根據(jù)團(tuán)隊(duì)的組織梧奢,軟件系統(tǒng)的各個(gè)部分的用法以及物理表現(xiàn)(代碼以及數(shù)據(jù)庫(kù)模型等)來(lái)設(shè)置模型的邊界狱掂。在這些邊界中嚴(yán)格保持模型的一致性,而不要受到邊界之外問(wèn)題的干擾和混亂亲轨。
- bounded context不是module
- 將不同模型的元素組合在一起可能會(huì)引發(fā)兩類問(wèn)題:重復(fù)的概念和假同源趋惨。重復(fù)的概念指的是兩個(gè)模型元素實(shí)際上表示同一個(gè)概念。假同源指的是使用相同屬于的兩個(gè)人認(rèn)為是在討論同一件事瓶埋,但是實(shí)際上不是這樣的希柿。
14.2 模式:continuous integration
- 當(dāng)很多人在同一個(gè)bounded context中工作時(shí),模型很容易發(fā)生分裂养筒。如果將系統(tǒng)分解為更小的context曾撤,最終又難以保持集成度和一致性。
- continuous integration是指把一個(gè)上下文中的所有工作足夠頻繁的合并到一起晕粪,并使他們保持一致挤悉,以便當(dāng)模型發(fā)生分裂時(shí),可以迅速發(fā)現(xiàn)并糾正問(wèn)題巫湘。
- 團(tuán)隊(duì)成員之間通過(guò)經(jīng)常溝通來(lái)保證概念的集成装悲。團(tuán)隊(duì)成員必須對(duì)不斷變化的模型形成一個(gè)共同的理解昏鹃。
- 建立一個(gè)把所有代碼和其他實(shí)現(xiàn)工件頻繁的合并到一起的工程,并通過(guò)自動(dòng)化測(cè)試來(lái)快速查明模型的分類問(wèn)題诀诊。嚴(yán)格堅(jiān)持使用ubiquitous lanuage洞渤,以便在不同人的頭腦中演變出不同的概念時(shí),使所有人對(duì)模型達(dá)成一個(gè)共識(shí)属瓣。
14.3 模式:context map
- 其他團(tuán)隊(duì)中的人員并不是十分清楚context的邊界载迄,他們會(huì)不知不覺(jué)中做出一些更改,從而是邊界變得模糊或者互聯(lián)變得復(fù)雜抡蛙。當(dāng)不同的上下文必須互相連接時(shí)护昧,他們可能會(huì)互相重疊。
- 通過(guò)定義不同的上下文之間的關(guān)系粗截,并在項(xiàng)目中創(chuàng)建一個(gè)所有上下文的全局視圖惋耙,可以減少混亂
- 識(shí)別在項(xiàng)目中起作用的每個(gè)模型,并定義其bounded context熊昌。這包括非面向?qū)ο笞酉到y(tǒng)的隱含模型绽榛。為每個(gè)bounded contetx命名。并把名稱添加到ubiquitous language中浴捆。描述模型之間的聯(lián)系點(diǎn)蒜田,明確所有通信需要的轉(zhuǎn)換,并突出任何共享的內(nèi)容选泻。先將當(dāng)前的情況描繪出來(lái)冲粤,以后再做改變。
14.3.1 測(cè)試context的邊界
- 對(duì)各個(gè)bounded context的聯(lián)系點(diǎn)的測(cè)試特別重要
14.3.2 context map的組織和文檔化
- 兩個(gè)重點(diǎn)
- bounded context應(yīng)該有名稱页眯,以便于可以討論他們梯捕。這些名稱應(yīng)該被添加到團(tuán)隊(duì)的ubiquitous language中
- 每個(gè)人都應(yīng)該知道邊界在哪里,而且應(yīng)該能夠分辨出任何代碼段的context窝撵,或者任何情況的context
- 一旦定義了counded context傀顾,那么把不同的上下文的代碼隔離到不同的module中就再自然不過(guò)濾。
- 我們可以用命名規(guī)范來(lái)表明這一點(diǎn)碌奉,后者使用其他簡(jiǎn)單且不會(huì)產(chǎn)生混淆的機(jī)制
14.4 bounded context之間的關(guān)系
14.5 模式:shared kernel
- 當(dāng)不同的團(tuán)隊(duì)開(kāi)發(fā)一些緊密相關(guān)的應(yīng)用程序時(shí)短曾,如果團(tuán)隊(duì)之間不進(jìn)行協(xié)調(diào),即使短時(shí)間內(nèi)能夠取得快速進(jìn)展赐劣,但他們開(kāi)發(fā)的產(chǎn)品可能無(wú)法結(jié)合到一起嫉拐。最后可能不得不耗費(fèi)大量精力在轉(zhuǎn)換層上,并且頻繁的進(jìn)行改動(dòng)魁兼,不如一開(kāi)始就使用continuous integration那么省心省力婉徘,同時(shí)這也造成重復(fù)工農(nóng)工作,并且無(wú)法使用公共的ubiquitous language所帶來(lái)的好處
- 從領(lǐng)域模型中選出兩個(gè)團(tuán)隊(duì)都統(tǒng)一共享的一個(gè)子集。當(dāng)然盖呼,除了這個(gè)模型子集以外儒鹿,還包括與該模型部分相關(guān)的代碼子集,或數(shù)據(jù)庫(kù)設(shè)計(jì)的子集几晤。這部分明確共享的內(nèi)容具有特殊的地位约炎,一個(gè)團(tuán)隊(duì)在沒(méi)有與另外一個(gè)團(tuán)隊(duì)上商量的情況下不應(yīng)該擅自修改它。
- 共享內(nèi)核中必須集成自動(dòng)測(cè)試套件蟹瘾,因?yàn)樾薷墓蚕韮?nèi)核時(shí)章钾,必須通過(guò)兩個(gè)團(tuán)隊(duì)的所有測(cè)試
- shared kernel 通常是core domain,或者是一組generic subdomain(通用子領(lǐng)域)热芹,也可能是二者兼有。
14.6 模式:customer/supplier development team
- 在兩個(gè)團(tuán)隊(duì)之間建立一種米孔雀的客戶/供應(yīng)商關(guān)系惨撇。在計(jì)劃會(huì)議中伊脓,下游團(tuán)隊(duì)相當(dāng)于上游團(tuán)隊(duì)的客戶。根據(jù)下游團(tuán)隊(duì)的需求來(lái)協(xié)商需要執(zhí)行的任務(wù)并為這些任務(wù)做預(yù)算魁衙,以便于每個(gè)人都知道雙方的約定和進(jìn)度
- 兩個(gè)團(tuán)隊(duì)共同開(kāi)發(fā)自動(dòng)化驗(yàn)收測(cè)試报腔,用于驗(yàn)證逾期的接口,把這些測(cè)試添加到上游團(tuán)隊(duì)的測(cè)試套件中剖淀,以便作為其持續(xù)集成的一部分來(lái)運(yùn)行纯蛾。這些測(cè)試使上游團(tuán)隊(duì)在做出修改時(shí),不比擔(dān)心對(duì)于上游團(tuán)隊(duì)產(chǎn)生副作用纵隔。
14.7 模式:conformist(跟隨者)
- 通過(guò)嚴(yán)格遵從上游團(tuán)隊(duì)的模型翻诉,可以消除在bounded context之間進(jìn)行轉(zhuǎn)換的復(fù)雜性。盡管這會(huì)限制下游設(shè)計(jì)人員的風(fēng)格捌刮,而且可能不會(huì)得到理想的應(yīng)用程序模型碰煌,單選擇conformity模式可以極大的簡(jiǎn)化集成。此外绅作,這樣還可以與供應(yīng)商團(tuán)隊(duì)共享ubiquitous language芦圾。供應(yīng)商處于統(tǒng)治地位,因此最好使溝通變?nèi)菀锥砣稀K麄儚睦髁x的角度出發(fā)个少,會(huì)與你分享信息
14.8 模式:anticorruption layer
1.我們需要在不同的模型的關(guān)聯(lián)部分之間建立轉(zhuǎn)換機(jī)制,這樣模型就不會(huì)被未經(jīng)消化的外來(lái)模型元素所破壞
- 創(chuàng)建一個(gè)隔離層眯杏,以便于根據(jù)客戶自己的領(lǐng)域模型為客戶提供相關(guān)功能夜焦。這個(gè)層通過(guò)另一個(gè)系統(tǒng)現(xiàn)有接口與其進(jìn)行對(duì)話,而只需對(duì)那個(gè)系統(tǒng)做出很少的修改役拴,設(shè)置無(wú)需修改糊探。在內(nèi)部,這個(gè)曾在兩個(gè)模型之間進(jìn)行必要的雙向轉(zhuǎn)換
14.8.1 設(shè)置anticorruption layer接口
- anticorruption layer的公共接口通常以一組service的形式出現(xiàn),但偶爾也會(huì)采用entity的形式
14.8.2 實(shí)現(xiàn)anticorruption layer
- 對(duì)anticorruption layer設(shè)計(jì)進(jìn)行組織的一種方法是把它實(shí)現(xiàn)為facade科平、adaptor和轉(zhuǎn)換器的組合褥紫,外加兩個(gè)系統(tǒng)之間進(jìn)行對(duì)話所需要的通信和傳輸機(jī)制
14.8.3 一個(gè)關(guān)于防御的故事
14.9 模式:separate way
- 集成總是代價(jià)高昂,而有時(shí)獲益卻很小
14.10 模式:open host service
當(dāng)一個(gè)子系統(tǒng)必須與其他系統(tǒng)進(jìn)行集成時(shí)瞪慧,為每個(gè)集成都定制一個(gè)轉(zhuǎn)換層可能會(huì)減慢團(tuán)隊(duì)的工作速度髓考。需要維護(hù)的東西越來(lái)越多,而進(jìn)行修改的時(shí)候擔(dān)心的事情也會(huì)越來(lái)越多
定義一個(gè)協(xié)議弃酌,把你的子系統(tǒng)作為一組service供其他系統(tǒng)訪問(wèn)氨菇。開(kāi)放這個(gè)協(xié)議,以便于所有需要與你子系統(tǒng)的集成的人都可以使用它妓湘。當(dāng)有新的集成需求時(shí)查蓉,就增強(qiáng)并擴(kuò)展這個(gè)協(xié)議。但個(gè)別團(tuán)隊(duì)的特殊需求除外榜贴。滿足這種特屬于需求的方案是使用一次性的轉(zhuǎn)換器來(lái)擴(kuò)充協(xié)議豌研,以便使共享協(xié)議簡(jiǎn)單且內(nèi)聚
這種通信形式暗含了一些共享的模型詞匯,他們是service接口的基礎(chǔ)唬党。這樣鹃共,其他子系統(tǒng)就變成了open host (開(kāi)發(fā)主機(jī))的模型相連接。而其他團(tuán)隊(duì)則必須學(xué)習(xí)host團(tuán)隊(duì)所使用的專用術(shù)語(yǔ)驶拱。在一些情況下霜浴,使用眾所周知的published language作為交換模型可以減少耦合并簡(jiǎn)化理解。
14.11 模式:published language
- 兩個(gè)bounded context之間的模型轉(zhuǎn)換需要一個(gè)公共的語(yǔ)言
- 與現(xiàn)有領(lǐng)域模型進(jìn)行直接的轉(zhuǎn)換可能不是一種好的解決方案蓝纲。這些模型可能過(guò)于復(fù)雜或設(shè)計(jì)的較差阴孟。他們可能沒(méi)有被很好的文檔化。如果把其中一個(gè)模型作為數(shù)據(jù)交換語(yǔ)言税迷,它實(shí)質(zhì)上就被固定住了温眉,而無(wú)法滿足新的開(kāi)發(fā)需求。
- 把一個(gè)良好文檔化的翁狐、能夠表達(dá)出所需領(lǐng)域信息的共享語(yǔ)言作為公共的通信媒介类溢,必要時(shí)在其他信息與改語(yǔ)言之間進(jìn)行轉(zhuǎn)換
14.12 “大象”的統(tǒng)一
- 承認(rèn)多個(gè)互相沖突的領(lǐng)域模型實(shí)際上正式面對(duì)現(xiàn)實(shí)的做法,通過(guò)明確定義每個(gè)模型都使用的上下文露懒,可以維護(hù)每個(gè)模型的完整性闯冷,把清楚的看到要在兩個(gè)模型之間的創(chuàng)建任何特殊的接口的定義
14.13 選擇你的模型上下文策略
14.13.1 團(tuán)隊(duì)決策或更高層決策
- 團(tuán)隊(duì)必須決定在哪里定義bounded context,以及他們之間有什么樣子的關(guān)系懈词。這些決策必須由團(tuán)隊(duì)做出蛇耀,或者只是傳達(dá)給整個(gè)團(tuán)隊(duì)。
14.13.2 置身上下文中
14.13.3 轉(zhuǎn)換邊界
- 權(quán)衡以下因素來(lái)畫(huà)出bounded context的邊界坎弯,首選較大的bounded context
- 當(dāng)用一個(gè)統(tǒng)一模型來(lái)處理更多任務(wù)時(shí)纺涤,用戶任務(wù)之間的流動(dòng)更順暢
- 一個(gè)內(nèi)聚模型比兩個(gè)不同模型再加他們之間的映射更容易理解
- 兩個(gè)模型之間的轉(zhuǎn)換可能會(huì)很難
- 共享語(yǔ)言可以使團(tuán)隊(duì)溝通起來(lái)更清楚
- 首選較小的bounded context
- 開(kāi)發(fā)人員之間的溝通開(kāi)銷減少了
- 由于團(tuán)隊(duì)和代碼規(guī)模較小译暂,continuous integration 更容易了
- 較大的上下文要求更加通用的抽象模型,而掌握所需技巧的人員會(huì)出現(xiàn)短缺
- 不同的模型可以滿足一些特殊需求撩炊,或者能夠把一些特殊用戶群的專門術(shù)語(yǔ)和ubiquitous language 的專門術(shù)語(yǔ)包括進(jìn)來(lái)
14.13.4 接收那些我們無(wú)法更改的事務(wù):描述外部系統(tǒng)
14.13.5 與外部系統(tǒng)的關(guān)系
14.13.6 設(shè)計(jì)中的系統(tǒng)
14.13.7 用不同模型滿足特殊需要
14.13.8 部署
14.13.9 權(quán)衡
14.14 轉(zhuǎn)換
14.14.1 合并context:separate way-》shared kernel
14.14.2 合并context:shared kernel-》continueous integration
14.14.3 逐步淘汰遺留系統(tǒng)
14.14.4 openhost service -》 pulished language
第15章 精煉
- 精煉是把一堆混雜在一起的組件分開(kāi)的過(guò)程外永,以便通過(guò)某種形式從中提取最重要的內(nèi)容,而這種形式就使它更有價(jià)值拧咳。
- 領(lǐng)域模型的戰(zhàn)略精煉包括一下部分
- 幫助所有團(tuán)隊(duì)成員掌握系統(tǒng)的總體設(shè)計(jì)以及各部分如何協(xié)調(diào)
- 找到一個(gè)具有適度規(guī)模的核心模型并把它添加到通用語(yǔ)言中伯顶,從而促進(jìn)溝通
- 指導(dǎo)重構(gòu)
- 專注于模型中最有價(jià)值的部分
- 指導(dǎo)外包、現(xiàn)成組件的使用以及任務(wù)委派
-
戰(zhàn)略精煉的系統(tǒng)方法
15.1 模式:core domain
- 對(duì)模型進(jìn)行提煉骆膝。找到core domain并提供一種易于區(qū)分的方法把它與那些起輔助作用的模型和代碼分開(kāi)祭衩。最有價(jià)值和最專業(yè)的概念要輪廓分明,盡量壓縮core domain
- 讓最有才能的人開(kāi)發(fā)core main阅签。掐暮,并據(jù)此要求進(jìn)行相應(yīng)的招聘。在core domain中牡蠣開(kāi)發(fā)能夠確保實(shí)現(xiàn)的系統(tǒng)藍(lán)圖的深層模型和柔性設(shè)計(jì)政钟。仔細(xì)判斷任何其他部分的投入劫乱,看它是否能支持這個(gè)提煉出來(lái)的coore。
15.1.1 選擇核心·
- 對(duì)core domain的選擇取于看問(wèn)題的角度
15.1.2 工作的分配
- 建立一支由開(kāi)發(fā)人員和一位或者多位領(lǐng)域?qū)<医M成聯(lián)合團(tuán)隊(duì)锥涕,其中開(kāi)發(fā)人員將必須能力很強(qiáng),能夠長(zhǎng)期穩(wěn)定的工作并且學(xué)習(xí)領(lǐng)域知識(shí)非常感興趣
- 自主研發(fā)的軟件最大價(jià)值來(lái)自于對(duì)于core domain 的完全控制
15.2 精煉的逐步提升
15.3 模式:generic subdomain
- 模型中有些部分除了增加復(fù)雜性意外并沒(méi)有捕捉或者傳遞任何專門的知識(shí)狭吼。任何外來(lái)因素都會(huì)對(duì)core ddomain愈發(fā)的難以分辨和理解层坠。模型中充斥著大量眾所周知的一般原則,或者是專門的細(xì)節(jié)刁笙,這些細(xì)節(jié)并不是我們的主要關(guān)注點(diǎn)破花,而只是起到支持作用。ranger疲吸,無(wú)論他們是多么的通用的元素座每,他們對(duì)于實(shí)現(xiàn)系統(tǒng)功能和充分表達(dá)模型都是極為重要的
- 識(shí)別那些與項(xiàng)目意圖無(wú)關(guān)的內(nèi)聚子領(lǐng)域。把這些子領(lǐng)域的通用模型提取出來(lái)摘悴,并且放到單獨(dú)的module中峭梳,任何專有的東西不應(yīng)該放在這些模塊中
- 把他們分離出來(lái)以后,在繼續(xù)開(kāi)發(fā)的過(guò)程中蹂喻,他們的優(yōu)先級(jí)地域core domain的優(yōu)先級(jí)葱椭。可以考慮為這些generic subdomain使用現(xiàn)成的方案或“公開(kāi)發(fā)布的模型”
- 開(kāi)發(fā)generic domain方案:
- 現(xiàn)成的解決方案
- 公開(kāi)發(fā)布的設(shè)計(jì)或模型
- 把實(shí)現(xiàn)外包出去
- 內(nèi)部實(shí)現(xiàn)
15.3.1 通用不等于可重用
15.3.2 項(xiàng)目風(fēng)險(xiǎn)管理
15.4 模式:domain vision statement
- 寫(xiě)一份core domain的簡(jiǎn)短描述以及它將會(huì)創(chuàng)造的價(jià)值口四,也就是“價(jià)值主張”孵运。那些不能將你的領(lǐng)域模型與其他領(lǐng)域模型區(qū)分開(kāi)就不要寫(xiě)了。展示出領(lǐng)域模型是如何實(shí)現(xiàn)和均衡各方利益的蔓彩。這份描述要盡量精簡(jiǎn)治笨。盡早把它寫(xiě)出來(lái)驳概,隨著新的理解隨時(shí)修改它
- domain vision statement為團(tuán)隊(duì)提供了統(tǒng)一的方向。但是高層次的說(shuō)明和代碼或者模型的完整細(xì)節(jié)之間通常還需要做一些銜接
15.5 模式:highlighted core
- 盡管團(tuán)隊(duì)的成員可能知道核心領(lǐng)域是由什么構(gòu)成的旷赖,但是core domain中到底包含哪些元素顺又,不同的人會(huì)有不同的理解,甚至同一個(gè)人在不同的時(shí)間也會(huì)有不同的理解杠愧。如果我們總是要不斷過(guò)濾模型以便于識(shí)別出關(guān)鍵部分待榔,那么就會(huì)分散本應(yīng)該投入到設(shè)計(jì)上的精力,而且這還需要廣泛的模型知識(shí)流济。锐锣。因?yàn)椋琧ore domain必須要很容易被分辨出來(lái)绳瘟。
- 對(duì)代碼所做的重大結(jié)構(gòu)性改動(dòng)是識(shí)別core domain的理想方式雕憔,但這些改動(dòng)往往無(wú)法在短期內(nèi)完成。事實(shí)上糖声,如果團(tuán)隊(duì)的認(rèn)識(shí)還不夠全面斤彼,這樣的重大代碼修改是很難進(jìn)行的
15.5.1 精煉文檔
- 創(chuàng)建一個(gè)單獨(dú)文檔來(lái)描述和解釋core domain。為讀者提供一個(gè)總體視圖蘸泻,指出了各個(gè)部分是如何組合到一起琉苇,并且指導(dǎo)讀者到相應(yīng)的代碼部分尋找更多細(xì)節(jié)。
- 編寫(xiě)簡(jiǎn)短的文檔悦施,用于描述core domain以及core 元素之間的主要交互過(guò)程
15.5.2 標(biāo)明core
15.5.3 把精煉文檔作為過(guò)程工具
- 如果精煉文檔概括了core domain的核心元素并扇,那么它可以作為一個(gè)指示器-用于指示模型改變的重要程度。當(dāng)模型或者代碼的修改影響到精煉文檔時(shí)抡诞,需要與團(tuán)隊(duì)其他成員一起協(xié)商穷蛹。
15.6 模式:cohesive mechanism
- 把概念上的cohesive mechanism(內(nèi)聚機(jī)制)分離到一個(gè)單獨(dú)的輕量級(jí)框架中。要特別注意公式或那些有完備文檔的算法昼汗。
15.6.1 generic subdomain 與cohesive mechanism的比較
15.6.2 mechanism是core domain的一部分
15.7 通過(guò)精煉得到聲明式風(fēng)格
15.8 模式:segregated core(分離的核心)
- 對(duì)模型進(jìn)行重構(gòu)肴熏,把核心概念從支持元素中分離出來(lái),并增強(qiáng)core的內(nèi)聚性顷窒,同時(shí)較少它與其他代碼的耦合蛙吏。把所有通用預(yù)算或者支持性元素提取到其它對(duì)象中,并把這些對(duì)象放到其他包中鞋吉。
- 通過(guò)重構(gòu)得到segregated core的一般步驟如下所示
- 識(shí)別出一個(gè)core的子領(lǐng)域
- 把相關(guān)的類轉(zhuǎn)移到新的module中出刷,并根據(jù)與這些類有關(guān)的概念為模塊命名
- 對(duì)代碼進(jìn)行重構(gòu),把那些不直接標(biāo)識(shí)概念的數(shù)據(jù)和功能分離出來(lái)坯辩。
- 對(duì)新的segregated core module進(jìn)行重構(gòu)馁龟,使其中的關(guān)系和交互變得更簡(jiǎn)單、表達(dá)更清楚
- 對(duì)另一個(gè)core 子域重復(fù)這個(gè)工程漆魔,直接完成segregated core的工作
15.8.1 創(chuàng)建segregated core的代價(jià)
15.8.2 不斷發(fā)展演變的團(tuán)隊(duì)決策
15.9 模式:abstract core
- 把模型中最基本的概念識(shí)別出來(lái)坷檩,并分離到不同的類却音、抽象類、接口中矢炼。設(shè)計(jì)這個(gè)抽象模型使之能夠表達(dá)出重要組件之間的大部分交互系瓢。把這個(gè)完成的抽象模型放到塔自己的module中,而專用的句灌,詳細(xì)的實(shí)現(xiàn)類留在由子領(lǐng)域定義的module中
15.10 深層模型的精煉
15.11 選擇重構(gòu)目標(biāo)
第16章 大型結(jié)構(gòu)
16.1 模式:evolving order
- 當(dāng)發(fā)現(xiàn)一種大型結(jié)構(gòu)可以明顯使系統(tǒng)變得更清晰夷陋,而又沒(méi)有對(duì)模型開(kāi)發(fā)施加一些不自然的約束時(shí),就應(yīng)該采用這種結(jié)構(gòu)胰锌。使用不合適的結(jié)構(gòu)還不如不使用它骗绕,因此最好不要為了追求設(shè)計(jì)的完整性而勉強(qiáng)去使用一種結(jié)構(gòu)。
16.2 模式:system metaphor(系統(tǒng)隱喻)
- 隱喻
16.3 模式:responsibility layer
- 如果每個(gè)對(duì)象的職責(zé)都是人為分配的资昧,將沒(méi)有統(tǒng)一的指導(dǎo)原則和一致性酬土,也沒(méi)有把領(lǐng)域作為一個(gè)整體來(lái)處理。為了保持大模型的一致格带,有必要在職責(zé)分配上實(shí)施一定的機(jī)構(gòu)化控制撤缴。
- relaxed layered:松散分層系統(tǒng)
- 決策支持層
- 作業(yè)職責(zé)
- 能力職責(zé)