DDD的基本概念 — 聚合与聚合根

一个系统中会有很多的实体类(包含值对象),这些实体类之间有的关系紧密,有的关系很弱,有的没有关系。

面向对象设计是一个重要原则就是”高内聚,低耦合”,我们同样希望有关系的实体类紧密协作,而关系很弱或者没有关系的实体类可以很好地被隔离。

因此,我们可以把关系紧密的实体类放到一个聚合(aggregate)中,每个聚合中有一个实体类作为聚合根(aggregate root)。

所有对聚合内实体类的访问都通过聚合根进行,外部系统只能持有对聚合根的引用,聚合根不仅仅是实体类,还是所有聚合的管理者。

聚合并不是简单地把实体类组合在一起,而要协调聚合内若干实体类的工作,让它们按照统一的业务规则运行,从而实现实体类数据访问的一致性,这样我们就能够实现聚合内的”高内聚”;

聚合之间的关系很弱,一个聚合只能引用另外一个聚合的聚合根,这样我们就能够实现聚合间的”低耦合”。

聚合体现的是现实世界中整体和部分的关系,比如订单与订单明细。

整体封装了对部分的操作,部分与整体有相同的生命周期。

部分不会单独与外部系统交互,与外部系统的交互都由整体来负责。

聚合的设计是DDD中比较难的工作,因为系统中很多实体类都存在着关系,这些关系到底是设计为聚合之间的关系还是聚合之内的关系是非常容易让人困惑的。

判断的标准就是看它们是否是整体和部分的关系,是否存在着相同的生命周期,如果是的话,它们就是聚合内的关系,反之,则不是。

比如,订单与订单明细之间显然是整体和部分的关系,因为删除了订单,订单明细也就消失了,而且外部系统不会直接引用订单明细,只会引用订单。

因此我们把订单和订单明细设计为一个聚合,并且把订单作为聚合根,外部系统只能引用订单,对订单明细的操作都通过订单来进行。

而用户和订单之间的关系就不是整体与部分的关系,因为删除了订单,用户还是可以存在的。

有人可能会认为,删除了用户,这个用户的订单也就消失了,因此用户和订单是整体和部分的关系。

但是聚合关系还有一个判断标准就是”实体类能否单独和外部系统交互”,很显然,在系统中订单是可以单独和外部系统交互的,比如支付系统中就可以直接引用订单,因此用户和订单之间不是聚合关系。

有的情况下,聚合关系的划分也不是一成不变的,不同的业务流程决定了不同的划分方式。

比如新闻和新闻的评论就既可以设计成同一个聚合,也可以放到不同的聚合中。

如果在网站中,新闻和评论都是一起出现的,评论不会单独出现,我们就可以把它们设计成同一个聚合,把新闻设置为聚合根。

但是如果在网站中,有”全站热门评论榜””分享评论到朋友圈”等把评论作为一个独立的实体类看待的情况,我们就可以把新闻和评论设置为两个聚合。

在设计聚合的时候,要尽量把聚合设计得小一点儿,一个聚合只包含一个聚合根实体类和密不可分的实体类,实体类中只包含最小数量的属性。

小聚合有助于进行微服务的拆分,也有助于减少数据修改冲突。

设计聚合的一个原则就是:聚合宁愿设计得小一点儿,也不要设计得太大。

在实践中,一个微服务中可以包含多个聚合。

由于聚合之间的关系都是聚合根之间的关系,因此耦合性低。

当我们需要进行微服务架构演进的时候,我们就能以聚合为单位轻松地进行微服务的拆分了。

这证明了DDD是指导微服务架构的强有力的思想。

订阅评论
提醒
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
滚动至顶部