首页 > 解决方案 > 聚合内部的实体可以在聚合外部访问或可见吗?

问题描述

我是 DDD 的新手,我的问题对你们中的许多人来说似乎微不足道。

考虑学生和课程的情况。

只有当学生的年龄高于注册该课程所需的最低年龄时,学生才能注册该课程。

从我的角度来看,Student 和 Course 可以被视为聚合,其中 Student 是根实体,Course 是子实体,age 是要尊重的不变量。

Student 应该有一个方法 Student.SubscribeTo(Course course) 并且该方法应该强制执行不变量Student.Age >= Course.MinAge,否则会生成异常。

这在 DDD 方法中是否正确?或者我应该只将 CourseId 传递给 SubscribeTo?Student.SubscribeTo(int CourseId)

从我的角度来看,如果没有办法打破不变量,则应该允许从外部访问 Course 到聚合。如果我在代码的其他一些地方更改 Course.MinAge,我不会破坏我的业务需求,因为我希望仅在订阅课程时尊重年龄,并且我不介意以后 Course.MinAge 是否更改。

如果业务需求声明不同的情况:当 Course.MinAge 更改时,已经注册该课程的学生应该从课程中删除 if Student.Age < Course.MinAge

标签: design-patternsarchitecturedomain-driven-designsoftware-design

解决方案


我认为您拥有的汇总不正确。Course 实体可以独立存在,它不是 Student 实体的子实体。课程有其自己的生命周期:例如,如果学生离开学校,课程将继续存在。课程 ID 不依赖于学生 ID。学生可以持有课程 ID,但它们是不同的聚合。

无论如何,对于您将课程 ID 传递给“student.subscribeTo”方法的问题(如果它们是一个聚合),答案是否定的,您不能将子实体的 ID 作为子实体传递给聚合的操作在聚合之外没有已知的全局身份。他们在聚合中具有本地 ID。

更新:

由于 Course 和 Student 是两个聚合体,因此“学生的年龄必须高于注册课程所需的最低年龄”的规则不是不变的。为什么?因为不变量是关于聚合状态的业务规则,所以它必须始终在事务上保持一致。聚合定义了事务一致性边界。

因此,该规则只是学生订阅课程时必须检查的验证规则(“student.subscribeTo”方法)。由于聚合不应使用存储库,因此您可以将域服务传递给该方法,并且学生聚合将双重分派到域服务,以便从课程 ID 获取课程。

查看 Vaughn Vernon 的 Red Book IDDD 的聚合章节(第 361-363 页)或同一作者的文章:

http://www.informit.com/articles/article.aspx?p=2020371&seqNum=4

希望能帮助到你。


推荐阅读