- 相關推薦
經典的領域驅動設計在代碼實踐方面的心得體會
創建領域對象采用構造函數或者工廠,如果用工廠時需要依賴于領域服務或倉儲,則通過構造函數注入到工廠;領域服務可以依賴倉儲或聚合根;
一個聚合根配備一個倉儲;
倉儲應理解為一個在內存中維護一系列聚合根的集合;
一個聚合有一個聚合根,聚合根也是一個Entity,聚合內還有其他Entity和Value Object;
倉儲提供的方法應該總是接受聚合根或返回聚合根,不能返回聚合內的其他Entity或Value Object;
聚合內的非跟的Entity以及Value Object之間不要相互引用,聚合內的所有Child可以對根Entity持有引用,如果一個Child Entity需要和另外一個Child Entity交互,則因該通過聚合根完成;
聚合根與聚合根之間應避免直接對象引用,而應該采用ID關聯;聚合根與聚合根之間的關系不像聚合內的Entity之間這么強烈內聚,它們之間僅僅是某種比較弱的關聯關系,每個聚合根都有其獨立的生命周期;
聚合根之間通過ID關聯的好處是:不會因為Load一個聚合根而把其他關聯的聚合根一起Load出來,這樣也避免了Load一個聚合根會把整個數據庫Load出來的風險;
我們應該盡量減少關聯,盡量做到單向關聯,只保留確實需要處理的經常需要用到的遍歷方向的關聯;
如果一個操作僅由一個聚合根就可以完成,那么直接調用該聚合根完成即可;
如果一個操作我們會遇見到會由多個聚合根相互協作完成,那么需要為該操作建立領域服務,在領域服務中以過程化的方式來一步步調用相關的聚合根完成整個業務操作;
切忌不要因為領域服務的引入讓聚合根變得貧血,聚合根應該有職責還是必須要由聚合根來承擔;
聚合根內不要依賴領域服務或倉儲,如果你發現一個聚合根的職責需要依賴于某個領域服務或倉儲來幫忙完成一些其他的邏輯(像判斷業務規則之類),那么通常你要考慮這個職責不應該由該聚合根來承擔,而應該建立合適的領域服務來承擔;聚合根的主要職責是管理其內聚的所有Child Entity或Value Object的業務完整性;
領域驅動設計時,為對象分配職責時,可以參考信息專家模式:將職責分配給擁有執行該職責所需信息的人;如果一個聚合根看起來擁有執行某個職責所需的信息,但沒包含全部所需信息,此時則不應該將該職責分配給該聚合根,因為強行分配給它,會導致該聚合根沒有內聚性,因為勢必會依賴于其它的領域對象或領域服務或倉儲;
聚合內的所有實體和值對象應該總是一起被取出來一起被保存,因為一個聚合是一個數據持久化的單元,不需要考慮將整個聚合根取出來有性能問題,因為任何一個聚合根都有明確的邊界。目前的內存緩存框架都已發展的比較成熟,性能已經不是問題;如MongoDb,MemCache,NoSQL,等等;
不要給倉儲提供一些目的是為了為界面提供顯示數據的接口,倉儲提供的所有接口僅為領域模型使用;
要學習CQRS架構,要知道我們應該將應用程序的業務邏輯處理部分(即用戶命令響應部分)和查詢部分分離;我們應該用兩個不同的技術來實現這兩個部分的實現;用DDD領域模型來實現命令部分;用最快的查詢引擎來實現查詢部分;
如果要采用CQRS架構,我們需要考慮一個成熟可靠的底層框架,否則很容易導致命令端產生的領域對象的狀態無法同步(后者丟失)到查詢端的存儲中;
領域服務依賴倉儲時,工廠依賴于領域服務或倉儲時,都因該采用構造函數注入的方式,這樣可以避免領域模型中不會出現DependencyResolver.Resolve<T>()這樣的語句;
不要把倉儲理解為DAO,倉儲屬于領域模型的一部分,代表了領域模型向外提供接口的一部分,而DAO是表示數據庫向上層提供的接口表示;
領域對象上的屬性可以具有get和set,因為我們平時所理解的對象不是真正的對象,而是某個事實的描述,比如圖書管理系統中的一個Book對象,表示圖書管中放著一本書,然后該書可能有一個入庫時間。現實生活正的話,書本的入庫時間絕對不可能變化,但是軟件中的Book因為不是真正的現實生活中的書本,而只是表示圖書館中有一本書這個事實的描述,我們當然可以修改這個事實,因為我們可能因為之前在書本入庫時所輸入的入庫時間是錯的,需要修改該入庫時間,此時就有提供set的必要了。所以,理論上任何一個Entity,除了ID之外,其他所有屬性都可以更改,因為這些屬性并不表示現實生活中的真正對象的特征,而僅僅只是對一個事實的描述;剛開始Book對象對書本入庫這個事實的描述可能有問題,此時我們就需要修改該Book的屬性;我想這個例子已經充分說明為什么可以提供get和set了;
不要總是零散的不加任何分組的設計Entity的屬性,因為有些屬性在邏輯上或業務上就是內聚的,代表一個完整的概念,比如Country,Province,City,Town,Street,等這些屬性表示一個地址的信息,此時我們應該設計一個Address對象來表示該地址信息,此時該Address就是一個值對象。所以我們在設計Entity的屬性時,要好好想想,哪些子屬性其實在業務上是一個完整的概念,此時我們就需要考慮將這些相關的屬性設計為一個值對象;
切忌值對象必須是只讀的,值對象之所以叫值對象最主要的是因為它表示一個值,而不是一個對象;值是不會變化的,是一個明確含義的不變的事物,比如3表示一個值,表述數量是3,3永遠不能變化;所以說,世界之所以存在,是因為有這些永恒不變的值對象的存在;我們只要把值對象理解為3,“abcd”這樣的永恒不變的值就行了;
不要讓領域模型去模擬現實,模擬用戶(軟件使用者)與領域模型交互的過程;領域模型要實現的應該是用戶的需求,領域模型中不應該包含用戶的成分,想想只有空杯子才能裝水的道理,即無為以之用的道理就明白了;所以,我們在設計領域模型時首先要明白領域模型要完成的事情是什么;這方面,多看看用例圖,就知道軟件該做的事情了,推薦大家看的書是:Craig Larman寫的《UML和模式應用》一書,非常經典;
暫時就寫這么多吧,以后想到什么再補上,呵呵。
【經典的領域驅動設計在代碼實踐方面的心得體會】相關文章:
幼兒園語言領域方面的教案(精選23篇)10-06
活動設計健康領域教案12-19
活動設計科學領域教案08-26
設計方崗位職責04-17
幼兒活動設計健康領域教案02-16
活動設計健康領域教案(7篇)12-24
活動設計健康領域教案7篇12-20
健康領域心得體會02-20
任務驅動型作文05-10
活動設計健康領域教案通用7篇12-27