聚合:如何聚合

聚合

  • 定义:将实体和值对象在一致性边界之内组成聚合
  • 聚合:体现了一套不变的业务规则 判断聚合关系的方法:如果整体不存在时,部分是否存在。如果不存在,就是聚合;反之如果整体不存在,部分仍然会存在,则他们之间不是聚合关系。

如何聚合

  • 找到事务一致性,即要求具有立即性和原子性,同时具备最终一致性
  • 在创建聚合时,主要关注的是一致性边界,而不是创建对象树
  • 尽可能的设计小聚合,减少维护一致性和不变性的成本
  • 大聚合可能会限制系统的性能和可伸缩性
  • 小的极端是,一个聚合只拥有一个全局标识和单个属性
  • 好的做法是,使用根实体(Root Entity)来表示聚合,其中只包含最小数量的属性和值类型属性
  • 聚合的属性:
    • 保留那些必须与其它属性保持一致的属性(当其中一个被改变,修改,其它的也会随之改变)
    • 聚合的属性优选值对象:测试简单、维护方便
  • 当一个用例需要修改多个聚合时,需要考虑是否需要重新建模聚合(因为一个用例的变化关注点应该是单一的)

实现

  • 通过唯一标识引用其他聚合
  • 引用聚合和被引用聚合不可以在同一个事务中进行修改(同时修改说明耦合,设计聚合时的一致性边界划定有问题)
  • 如果上面一条规则导致大聚合,那么可能需要引入最终一致性(即,各聚合在最终达到一致事务状态)
  • 那么如何解决对象之间交互完成任务的情况呢?
    • 通过标识引用使多个聚合协同工作
    • 建模对象导航性:可以在调用聚和行为之前,使用资源库或领域服务来获取所需要的对象
    • 避免在聚合中使用资源库或领域服务(处理复杂依赖关系中,在聚合方法中使用领域方法却是最好的解决方法)
  • 在边界之外使用最终一致性
    • 当在一个聚合上执行命令方法时,如果需要在其他聚合上执行额外的业务规则,那么使用最终一致性
    • 需要领域专家确认,对于修改不同聚合实例之间的时间延迟,他们是否可以接受,最终一致性方法:
      • 一个聚合的命令方法所发布的领域事件及时的发送给异步订阅放
      • 在接收到事件之后,每个订阅方都会获取自己的聚合实例,然后在该聚合上完成想要的操作
      • 每个订阅放都在单独的事务中进行操作,满足了一次事务只修改一个聚合实例的原则
  • 在一个事务中更新多个聚合实例的理由(妥协的理由):
    • 方便用户界面
    • 缺乏技术机制
    • 全局事务
    • 查询性能

参考文献

  1. 《实现领域驱动设计》 — Vaughn Vernon


blog comments powered by Disqus
—  原创作品许可 — 署名-非商业性使用-禁止演绎 3.0 未本地化版本 — CC BY-NC-ND 3.0   —