DDD中聚合划分的思考

原创
2019/07/24 17:22
阅读数 1.4K

在之前的《基于领域分析设计的架构规范-领域分析基础》一文中,我有介绍过关于聚合的概念,其中聚合中非根实体的判别,是依照其不能离开聚合根而单独存在,比如订单明细不能离开订单而存在,所以订单明细只属于订单聚合中的一个非根实体。

但我一直觉得还过于抽象,应该还有更严谨完善的判断方式。 所以,本文就一起来思考个案例:

案例背景

在一个资讯平台上,用户能登陆后发表文章,并阅读文章。所以,在一开始,两者的关系是这样的: 资讯平台关系图1

之后,来了一个新需求,说用户能够对文章发表评论,那么,评论这个实体,该如何设置呢?我们不妨思考一下:

  • 评论必然是归属给一个文章的,至少目前需求来看是这样,所以评论离不开文章
  • 评论必然也是一个用户发起的,评论也离不开用户
  • 看起来有点棘手...不过总之评论肯定不能独立存在了。

如果按我之前文章中提到的,很有可能就会陷入上面的思考了,很有可能会认为评论应该是“文章的评论”,所以评论应该是隶属于文章聚合的。

设计分析

但怎么看都觉得别扭啊!非常别扭!但按之前的规则来说,应该是这么回事呀,问题出在哪呢?

我们来思考:评论是如何创建的?产品流程如下:

用户在文章下方的评论框中输入评论,点击提交

那么代码上顺利成章应该就是这样:

   Comment comment = commentFactory.create(newCommentRequest);

但如果要强行用文章聚合的设计方案,就会非常别扭了:

   //既然聚合根是文章,那么肯定要先找到文章,再给文章加入评论
   Blog blog = blogRepository.getById(newCommentRequest.getBlogId());
   blog.addComment(newCommentRequest);

当然,“别扭”一词还不够严谨,换用一个更严谨的说法:

评论虽然与文章有关,但其创建过程并不是发生在文章的各项生命周期的操作中的,而是独立创建的,所以,它应该是一个新的独立的聚合

具体说来:文章有创建,编辑,审核,删除等等操作流程,但这个过程中,并不会产生评论,意味着,评论并不是文章生命周期中的直接衍生物,它虽然关联了文章,也关联了用户,但却是独立被创建,也有自己独立的生命周期(能被单独修改,单独删除)。

所以,关系图应该是

资讯平台关系图2

而相比之下,我们再看更常见的非根实体,比如用户登陆日志订单变更日志,这些实体,其创建的过程,都是在用户登陆,订单各项操作的过程中被创建出来的,生命周期的一开始就和根实体强绑定。

所以,这次,我总结了以下几个原则,来判断一个实体,是否应该作为一个新的领域聚合的根存在,判断的优先程度由高到低是:

  1. 该实体的创建过程是否是完全独立的,而非依赖与其他某个实体的命令操作;
  2. 该实体是否能被单独进行删/该操作,而非比如伴随其他某个实体的命令操作而变动;
  3. 该实体是否有单独的列表视图,而非必须依赖其他某个实体的视图作为前置条件(比如订单日志必须要先找到订单);

其中,(2)(3)只是作为一个辅助参考,最关键的还是(1),如果(1)能遵守了,十之八九可以定义为一个独立的聚合了。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部