DDD—聚合和聚合根

一、聚合
     上文讲到的实体和值对象,都只是带有业务逻辑的个体对象,表现的主要是个体属性和行为。所以在领域模型中需要一个组织,有序的组织起个体的行为,将紧密关联的个体对象聚集到一起,按照业务编排完成局部完整的业务逻辑。
     比如在学生和老师都是带有个体属性和实体,都有各自的行为,是靠校长把老师和学生聚合到学校里,按照学校的规章制度,教学方针组织起了学校教育的工作,而组织里的各项制度,都是老师和学生需要遵守的。
     多个聚合在同一个限界上下文和微服务内,在聚合中有个聚合根和上下文边界,这个边界比限界上下文要小,主要是根据业务的单一职责和高内聚设计原则,把涉及到这部分单一职责的实体和值对象聚合到一起,完成业务逻辑。
     聚合在领域模型里是个业务边界,没有业务逻辑实现相关的代码。
 
二、聚合根
     比如人是一种对象,男人是一个家庭的根(聚合根),对这个家庭的女人,小孩的他有绝对保护权,想欺负女人和小孩都得先问问男人的拳头,而男人,女人,小孩组成的家庭,就是一个聚合,男人就是这个聚合的聚合根
     又比如淘宝是一个领域,在组织架构的聚合里,马云是这个聚合的老大,马老板聚合了淘宝的业务,技术,产品,他就是这个聚合的聚合根,产品的思想,业务的发展,技术的投资,都是通过他点头的。
     聚合根和领域里的各种对象都是有各自独立属性的,比如男人的属性(养家,买车,买房),女人(教育,生小孩,持家)同时他们是相互依赖,不可分离的,聚合根不能离开他的子对象,而领域里的子对象也不能离开他的聚合根,否则就玩不下去了
     这样设计的原因是:聚合内有一定业务规则以确保聚合内数据的一致性,如果在实现业务逻辑时,任由服务对聚合内实体数据进行修改,那么很可能会因为在数据变更过程中失去统一的业务规则控制,导致聚合内实体之间数据逻辑的不一致。
     所以领域模型,就是我们先聊领域里聚合根和其他对象的属性,关联关系,再聊他们各自的行为,和可以干啥,他有哪些业务逻辑,逻辑方法。
 
三、聚合的特性
  • 聚合根是实体,拥有实体的业务属性和行为,同时也是聚合的管理者,负责协调聚合内的实体和值对象,按照固定的业务规则,完成业务逻辑。
  • 聚合根是聚合对外唯一的接口人,聚合之间以聚合根ID关联的方式接受聚合的外部任务和请求,聚合外不能通过对象引用的方式访问聚合内的对象。需要将关联的聚合根ID作为入参,先访问聚合根,再通过聚合根导航到聚合内部实体。
  • 如果聚合根被删除了,他引用的实体和值对象就不会存在了
  • 聚合根和聚合根所在层的领域服务都可以组合多个实体完成领域逻辑,但为了DDD分层架构的职责单一,聚合根最好只承担聚合管理职能,只实现聚合内实体和聚合根本身相关的业务逻辑,而跨多个实体的复杂领域逻辑统一放到领域服务中实现。
  • 领域建模中,可能存在一些独立的找不到聚合根的实体,但可以根据高度依赖的业务逻辑,把这些实体集合也作为聚合处理。
 
四、聚合的设计
  
  • 如图,第一步首先采用事件风暴,梳理网购领域中的业务行为和行为产生的实体,值对象
  • 从众多实体中找到适合作为聚合对象管理者的根实体,即聚合根(图中加深色的实体),我们可以根据这个实体是否贯穿整个软件的生命周期,是否有全局唯一ID,是否可以作为一个聚合管理者去管理其他实体和值对象来确定是不是聚合根
  • 将聚合根和关联的实体,值对象汇聚到多个聚合里,如图,用户和订单作为用户聚合和订单聚合的聚合根,汇聚了其他实体和值对象,形成用户和订单两个聚合,划分好了聚合间的上下文。
  • 找到聚合之间的引用,比如用户数据冗余到了订单聚合里的发件人和收件人,不至于用户聚合发生异常时,订单聚合也出现问题,订单聚合记录了发件人和收件人的快照数据
  • 遍历查看所有的聚合,看是否有与其他聚合相关的实体和值对象,遵循单一职责剥离出来归并到其他聚合中
 
五、聚合的设计原则
    《领域驱动设计》《基于DDD和微服务的中台架构与实现》一书中总结了聚合设计的原则
     1、聚合内要有一套不变的,基本长期固化的业务规则,而不是简单的将实体和值对象组合到一起,聚合的上下文边界要清晰,保证聚合边界外的任何东西与聚合无关
     2、聚合可以作为拆分微服务的最小业务单元,与Serverless完美的结合,但不适合过度拆分,除非业务需求
     3、聚合要高内聚,不宜设计得过大,会导致聚合内的实体和值对象膨胀从而不好管理
     4、聚合间的交互要通过聚合根ID应用其他聚合
  • 当领域模型随着业务需求的变化,微服务内需要进行更小粒度的拆分,即聚合层面的拆分,这样原本互相在微服务内互相依赖的聚合,就变成了服务间调用了,如果最开始在聚合内用对象应用的方式,那么服务拆分后就会失效,需要很大的代码调整
  • 采用聚合根ID应用的方式,则可以将聚合根ID和目标方法作为微服务的入参,实现跨微服务的调用,这种的改动方式会小很多,代码理解起来也会更加的清晰
     5、通过应用层实现领域服务的编排和组织,领域服务实现跨聚合的调用,组成业务逻辑
     6、在聚合内使用数据强一致性,在聚合外使用数据最终一致性。DDD强调在一次事务中,最多只能修改一个聚合的数据。如果涉及到多个聚合的数据修改,在微服务内可以使用事件总线,微服务外使用领域事件驱动,通过消息的最终一致性来保证
 
 
  

  参考书籍 ——《基于DDD和微服务的中台架构与实现》欧创新、邓頔
  参考书籍 ——《领域驱动设计》Eric Evans
  参考书籍 ——《架构真经》Martin L. Abbott

posted @ 2021-05-29 15:48  纪煜楷  阅读(6639)  评论(1编辑  收藏  举报