【发布时间】:2015-02-28 22:04:45
【问题描述】:
假设我们有class Home,并且我们希望在这个家中收集所有Cats,但我们还希望拥有Cats 的通用存储库,其中包含世界上所有可用的猫。 Home 是否应该保留对 Cats 的特定存储库(或可能是集合)的引用,还是应该在通用存储库中再次查找?
【问题讨论】:
标签: java oop design-patterns domain-driven-design
假设我们有class Home,并且我们希望在这个家中收集所有Cats,但我们还希望拥有Cats 的通用存储库,其中包含世界上所有可用的猫。 Home 是否应该保留对 Cats 的特定存储库(或可能是集合)的引用,还是应该在通用存储库中再次查找?
【问题讨论】:
标签: java oop design-patterns domain-driven-design
从领域驱动设计的角度来看,您不应该将一个聚合根 (AR) 实例包含在另一个 AR 实例中,而且通常一个实例也不会引用任何实体中的存储库。
所以如果Home 和Cat 都是AR,那么Home 应该只包含一个Cat ID 列表或一个值对象(VO)列表,每个都代表一只猫,例如HomeCat 包含 Id,也许还有 Name。这也促进了Home AR 周围的持久性,因为HomeRepository 将负责Home 和HomeCat 的持久性。
我必须承认,当 Entity (例如 Cat)包含在多个 AR 中时,它会变得有些奇怪。但是,您仍然不会在 home 对象中拥有 cat 存储库,而是让 HomeRepository 在检索相关的 home 实例时使用 CatRepository。
【讨论】:
Home 中的 id 集合?据我们所知,没有要强制执行的不变量,所以收集有点毫无意义。该关系通常应该从多对一建模,因此Cat 将通过身份引用它的Home。使用CatRepository,您可以轻松找到特定Home的所有Cat。
HomeRepository::getById() 申请以获得所需的Home 2. HomeRepository 获得@ 987654345@ 及其 CatIds 值对象的集合 3. HomeRepository 向注入的 CatRepository 发出请求,以获取所有 Cat 实例,将它们构造为 HomeCat 如果我理解得很好,一个问题:这样做,您将一个存储库耦合到另一个存储库,因此在Home 中使用CatId 值对象没有任何意义,因为我们最终没有任何好处,不是吗?谢谢!
Cat 是否是 AR。如果它是一个 AR,那么您应该不引用 Home 中的任何 Cat 实例。理想情况下,VO 应该包含不变位。比如说,您可以致电Home.add(someCatAR),它会在内部创建新的 VO。但是,如果Cat 是一个实体,您需要以某种方式将其添加到Home,并且我同意 that 有点麻烦。但是它就是这样啊。我会重新考虑设计。这可能是大多数人认为存储库只返回 AR 的原因。
HomeAddedEvent 等初始事件的结构仍将仅包含猫 ID,然后处理器将使用 CatQuery 获取相关的猫数据。
由于 Java 是基于引用的,因此您可以保留两个集合而不会造成任何严重损害。
您需要确保家中的每只猫也都在“世界”中。这里的问题是,如果您家中的猫变化很大,您将需要进行多次查找,因此您应该选择一种数据结构 data 尽可能快地实现这一点(我在想 hashMaps ..)
使用两个系列可以让您尽快找到家中的猫。但是同步集合可能是一个问题。在这种情况下,您可以考虑观察者模式:home 观察世界,如果猫死了,它会检查它是否在 home 中,然后删除...
有很多方法可以按照您的要求进行操作,您需要做的就是考虑频率较高的操作是什么,以及您的总体需求。如果收藏品很小,那么拥有一个收藏品没有问题,通过查找找到猫的家......
【讨论】:
如果Cat 需要是CatRepository 可访问的其自身聚合的聚合根,那么它应该不包含在Home 聚合中。您的Home 实体应通过身份而不是通过引用来引用关联的Cat 实体。
这是一个聚合设计问题,需要仔细研究您的域以及您需要如何使用您的实体。您可以问自己的一个问题是“如果我删除Home,是否也应该删除所有Cat 实体?”不要过分强调这个问题。还有其他重要因素需要考虑。
Vaughn Vernon 在他的三部分 PDF 系列 Effective Aggregate Design 中讨论了这个主题。
【讨论】:
很难用虚构的域(或至少关于它的很少信息)回答 DDD 问题,因为 DDD 就是按原样对域进行建模并保持其不变量的完整性。
据我所知,您没有任何适用于Home 和Cat 之间关系的不变量,因此您不需要Home 的一致性边界内的Cat 对象集合.您可以简单地拥有两个聚合根(Home 和 Cat),Cat 将通过 identity 引用它的 Home。
您可以使用CatRepository 查询来自特定家庭的所有猫或独立于其家庭的所有猫。
不要在模型中放置人为约束,这一点很重要。例如,如果您在Home 中持有Cat 身份的集合,仅出于维护关系的目的,那么您限制了系统的可伸缩性:两个同时发生的事务试图将新的Cat 关联到同一个Cat Home 将无缘无故地失败并出现并发异常(假设是乐观并发)。
【讨论】: