聚合(Aggregate) 是 DDD 中的一个重要模式。
不变规则
在领域对象的整个命周期都是有效的,不会有时候有效,有时候又无效了。
聚合的特征
- 具有整体与部分的关系
- 具有不变规则,而且这种不变规则在并发的时候可能被破坏
聚合的表示法
<< aggregate root >> 的标识
- 中文是聚合根的意思
- 是两个小于号和两个大于号
- 这个符号在 UML 里叫做 stereotype ,中文译作衍型。这是 UML 里用来扩充符号意思的一种机制
- 有菱形的一端是代表“整体”的对象,另一端是代表“部分”的对象
- 整体部分关系是关联关系的一种特例
- 出于简洁的原因,整体端的 “1..1” 被删掉了。因为,对于这种整体部分关系而言,这一端必然是 “1..1”
- 用一个包把这个聚合中的类包起来,从而可以一眼看出这个聚合的边界
- 一般约定,聚合包的名字和聚合根的名字是一样的
在一个聚合里,像员工这样代表整体的实体就是聚合根。一个聚合只有一个聚合根。
派生关联(derived association)
用一个领域对象推导出另一个领域对象称为派生关联。
例如:因为领域专家希望强调当前客户经理这个概念,所以由客户经理推导出了当前客户经理。
“/ 当前客户经理”前面有一个斜杠。在 UML 中,凡是前面有斜杠的,就表示是派生出来的内容。
更多聚合概念
- 作为部分的实体,只能属于一个聚合根,不可能属于多个聚合根。比如说,一条技能信息,只能属于一个员工,不能属于多个员工。又比如说,我的手只能是我一个人的手,不能同时又是其他人的手。
- 一个聚合的一部分,不能再变成其他聚合根的一部分。比如说,我的手是不能“跳槽”的。不能今天是我的手,明天就变成了别人的手。
- 由前两条自然可以推出,聚合根被删除,那么聚合中的所有对象都会被删除。
- 在业务上,为了识别每个实体,实体必然要有一个标识。例如,人的标识,可以是身份证号。如果这个人是学生,那么他的标识也可以是学号。注意,这里说的标识是一个业务概念,而不是技术概念,和数据库表中常见的没有业务概念的 ID 是不同的。
对于聚合而言,聚合根要有全局的唯一标识,而从属于聚合根的实体只需要有局部于聚合的标识。例如,员工是聚合根,员工号是全局标识。而工作经验没有必要进行全局编号,只需要在聚合内部编个号就可以了。例如,001 号员工的第 1 份工作经验、第 2 份工作经验等等。
聚合的作用
- 基本的作用是为一组具有整体部分关系的对象维护不变规则
- 提供了一个新的视角,可以更细致地和业务人员讨论业务规则
- 聚合在业务规则和事务之间建立了起联系:事务其实是来源于业务规则的,本质上是个业务问题
- 模型的层次就变得更清晰了:在模型上为每个聚合建了一个包,可以认为,聚合是一种特殊的模块
- 降低了认知负载:可以把聚合当作一个粗粒度的概念单位进行思考
- 聚合作为一个事务边界,给出了事务范围的下限,为开发时确定事务范围提供了参考