[實現DDD] 第10章 聚合(1)設計原則
聚合只是將一些實體(Entity)與值對象(Value Object)聚集起來的對象樹嗎??
有些途徑可能使我們設計出不正確的聚合模型, 如:可能為了對象組合上的方便而將聚合設計的很大;也可能設計的聚合過於貧瘠而喪失了保護真正不變條件(業務規則)的目的。
"實現領域驅動設計"一書的作者,提供了幾個聚合設計原則......
- 在一致性邊界之內建模真正的不變條件
這裡的不變條件指的是一個業務規則,該規則應該總是保持一致的。存在多種類型的一致性,事務一致性(高一致性),最終一致性等。
在討論不變條件時,就是在討論事務一致性。聚合邊界內的對象,可能都實現了某種不變條件,在此邊界內的所有內容組成了一套不變的業務規則。
任何操作都不能違背這些規則,邊界之外的任何東西與該聚合都是不相關的。因此,聚合表達了與事務一致性相同的意思。
設計聚合時,我們需要慎重考慮一致性,這意味著每次客戶請求應該只在一個聚合實例上執行一個命令方法。小結
聚合是為了封裝真的不變性,而不是單純的將對象組合起來
- 設計小聚合
對於大聚合,即便可以成功地保持事務一致性,但它可能限制了系統性能和可伸縮性。 系統可能隨著時間可能會有越來越多的需求與用戶,開發與維護的成本我們不應該忽視。
怎樣的聚合才算是"小"聚合呢??
好的做法是使用根實體(Root Entity)來表示聚合,其中只包含最小數量的屬性或值類型屬性。哪些屬性是所需的呢??簡單的答案是:那些必須與其他屬性保持一致的屬性。
比如,Product聚合內的name與description屬性,是需要保持一致的,把它們放在兩個不同的聚合顯然是不恰當的。
優先選擇值對象
使用值對象有很多好處
(1) 根據持久化機制,值對象可以隨著根實體而序列化,需實體則需要單獨存儲區域予以跟踪。
(2) 實體會帶來一些不必要的操作,比如,在資料庫中我們需對多張表進行聯合查詢 ;而使用值對象只需對單張表查詢,也更安全方便。
(3) 由於值對象是不變的,測試起來也相對簡單。
如果你認為有些被包含部分應建模成實體,那應該先思考一下,這個部份是否會隨時間而改變,或該部分是否能被全部替換。如果可以全部替換,請建模成值對象,而非實體。
小結
小聚合的好處不僅有性能和可伸縮性上的好處,它還有助於事務的成功執行,即它可以建少事務提交衝突。如此一來,系統可用性也得到了增強。
聚合內高一致性,聚合之間最終一致性。
- 通過唯一標識引用其他聚合
Evans寫到,一個聚合可以引用另一個聚合的根聚合,但此時被引用的聚合不應該放在引用聚合的一致性邊界內。錯誤的引用聚合只會讓聚合邊界模糊而已。
在不持有對象引用情況下,我們是不能修改其他聚合的,因此我們可以避免在同一事務中修改多個聚合。但這種方式缺點在於限制性太強,那我們該怎麼辦呢??
通過標識引用使用多個聚合協同工作
這種方式好處創建的聚合也會變的更小,此時所關聯的聚合不會即時加載,模型的性能也隨之變好。
建模對象導航性
通過標識引用並不意外我們完全失了對象導航性,這種技術稱為失聯領域模型(Disconnected Doamin Model),而事實上這僅是一種延遲加載的形式。
另外一種推薦的作法:在調用聚合行為方法之前,使用資料庫或領域服務來獲取所需的對象。小結
唯一標識引用對象在缺點在於在用戶界面層,要組裝多個聚合並予以顯示將變的因難,有損模型使用的方便性;但其他的好處是,小聚合可增強模型的性能和可伸縮性,另外有助於創建分布式系統。
最後強調,我們應避免一個事務操作多個聚合。
- 在邊界之外使用最終一致性
如果單次用戶請求需要修改多個聚合實列又需要證模型的一致性時,以下是Evans對聚合模式的定義 ,
任何跨聚合的業務規則都不能總是保持最新狀態。通過事件處理,批處理或者其他更新機制,我們可以在一定時間之肉處理好他方依賴。[Evans, p.128]
在一個大規模,高吞吐的企業系統中,要使所有的聚合實例完全一致是不可能的。認識這點,你便知道在較小規模的系統中使用最終一致性是必要的。
在DDD中,有一種很實用的方法可以支持最終一致性,即一個聚合命令方法發布領域事件及時地發送給異步的訂閱方;在接收到事件之後,每個訂閱方都會獲取自己的聚合實例,然後在該聚合上完成相庄操作。每個訂閱方都在單獨的事務中進行操作,也即滿足了"在一個事務中只修改一個聚合實例"的原則。
小結
在某些場景下,我們很難決定應該採取事務或是最終一致性,書中提出了一個簡單且實用的指導原則。對於一個用例,問問是否應由執行該用例的用戶來保證數據的一致性?如果是請使用事務一致性;若要其他用戶或者系統來保證數據一致性,請使用最終一致性。
以上的原則都是可以打破的,但在此之前必須要有充足的理由,那會有什麼樣的理由呢?下一篇再由書中摘錄吧。。。。。
[實現DDD] 第10章 聚合(1)設計原則的更多相关文章
- [實現DDD] 第11章 工廠
創建過程中須考慮一些重要細節, 否則所創建的聚合將處於不正確的狀態, 使用適當的工廠方法可以確保這一點, 而客戶端只需輸入基本的參數(通常是值對象), 另外, 工廠能更好地表達出通用語言, 使團隊成員 ...
- 应用程序框架实战十八:DDD分层架构之聚合
前面已经介绍了DDD分层架构的实体和值对象,本文将介绍聚合以及与其高度相关的并发主题. 我在之前已经说过,初学者第一步需要将业务逻辑尽量放到实体或值对象中,给实体“充血”,这样可以让业务逻辑高度内聚, ...
- DDD分层架构之聚合
DDD分层架构之聚合 前面已经介绍了DDD分层架构的实体和值对象,本文将介绍聚合以及与其高度相关的并发主题. 我在之前已经说过,初学者第一步需要将业务逻辑尽量放到实体或值对象中,给实体“充血”,这样可 ...
- [Xamarin.Android] 結合Windows Azure與Google cloud message 來實現Push Notification (转帖)
這一篇要討論如何使用Xamarin.Android 整合GCM以及Windows Azure來實作Android手機上的推播通知服務. 這篇文章比較著重概念的部分,在開始讀這篇之前,也可以先參考一下X ...
- Neo4j中實現自定義中文全文索引
資料庫檢索效率時,一般首要優化途徑是從索引入手,然後根據需求再考慮更復雜的負載均衡.讀寫分離和分散式水平/垂直分庫/表等手段:索引通過資訊冗餘來提高檢索效率,其以空間換時間並會降低資料寫入的效率,因此 ...
- 《构建之法》之第8、9、10章读后感 ,以及sprint总结
第8章: 主要介绍了软件需求的类型.利益相关者,获取用户需求分析的常用方法与步骤.竞争性需求分析的框架NABCD,四象限方法以及项目计划和估计的技术. 1.软件需求:人们为了解决现实社会和生活中的各种 ...
- 敏捷软件开发:原则、模式与实践——第10章 LSP:Liskov替换原则
第10章 LSP:Liskov替换原则 Liskov替换原则:子类型(subtype)必须能够替换掉它们的基类型(base type). 10.1 违反LSP的情形 10.1.1 简单例子 对L ...
- 孙鑫视频学习:对第10章设置线宽时为什么不调用UpDateData(TRUE)的理解
在第10章10.2.1小节中,首先分别对视图类和对话框类添加了一个名为m_nLineWidth的int型变量,再将用户在CSetting dlg对话框的edit控件中输入的线宽值记录在dlg.m_nL ...
- 第10章 系统级I/O
第10章 系统级I/O 10.1 Unix I/O 一个Unix文件就是一个m个字节的序列:B0,B1,…,BK,…,Bm-1 Unix I/O:一种将设备优雅地映射为文件的方式,允许Unix内核引出 ...
随机推荐
- IDEA的一些常用快捷键以及配置
IDEA常用快捷键: 保存:ctrl + s 关闭当前文件:ctrl + F4 撤销:ctrl + z 反撤销:ctrl + shift + z 查看方法实现类:ctrl + alt + B 移动 ...
- struts2配置文件的解释
1 <?xml version="1.0" encoding="GB2312"?> <!DOCTYPE struts PUBLIC &quo ...
- React + Dva + Antd + Umi 概况
Dva 由阿里架构师 sorrycc 带领 team 完成的一套前端框架,在作者的 github 里是这么描述它的:"dva 是 react 和 redux 的最佳实践". Ant ...
- 【SSO单点系列】(4):CAS4.0 SERVER登录后用户信息的返回
接着上一篇,在上一篇中我们描述了怎么在CAS SERVER登录页上添加验证码,并进行登录.一旦CAS SERVER验证成功后,我们就会跳转到客户端中去.跳转到客户端去后,大家想一想,客户端总要获取用户 ...
- [Swift实际操作]九、完整实例-(3)创建和安装开发证书、发布证书及开发证书配置文件、发布证书配置文件
本文将为你演示,如何创建开发证书和发布证书,以及其他辅助内容.首先打开浏览器,进入[苹果开发者网站]输入[Apple ID]和[密码],点击登录按钮,进入开发者管理后台. 点击左侧的[Membersh ...
- 关于C语言中printf函数“输出歧视”的问题
目录 关于C语言中printf函数"输出歧视"的问题 问题描述 探索问题原因 另一种研究方法 问题结论 关于C语言中printf函数"输出歧视"的问题 问题描述 ...
- 流水的算法,铁打的损失函数/MLE
机器学习算法可以说是不少的,如果死记硬背的话,只能当时记得推导过程和步骤,过一段时间就又想不起来了,只能依稀记得一些影子.所以,应该找到算法的一些通用的方法来理解算法的思路以及推导过程. 我认为,最大 ...
- Python之路Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数
Python之路Python作用域.匿名函数.函数式编程.map函数.filter函数.reduce函数 一.作用域 return 可以返回任意值例子 def test1(): print(" ...
- controller运行springboot项目
搭建完springboot项目后,新建HelloController.java文件,编写main方法,启动HelloController.java,具体代码如图: 在浏览器访问127.0.0.1:80 ...
- iOS苹果和微信中音频和视频实现自动播放的方法
通过下面的方式可以解决,在iPhone手机微信中正常自动播放. 必须在微信Weixin JSAPI的WeixinJSBridgeReady才能生效,猜测微信接口做了处理~ <audio prel ...