领域驱动设计——大型子集合

本文关键字:大型 子集合 | 更新日期: 2023-09-27 18:02:18

问题

如何在DDD中实现大型集合,"感觉"它们应该是聚合根的一部分,但如果它们是则不切实际?下面是一些基于我的领域的例子。

Employee聚合根

  • Announcements Collection
  • 直接Messages收集

Product Aggregate Root

  • Stock物品收集

等。等

我在想什么

我想保持从聚合根导航到这些大型集合的能力,但因为我正在用存储库包装我的O/RM,所以延迟加载不是一个真正的选择…除非我通过注入必要的存储库来实现延迟加载。但是从我读到的关于DDD的知识中我知道域实体不应该知道任何这样的存储库。

另一种选择是采用这样的方法,即我的域中的任何潜在的大型实体集合都是聚合根,并且应该具有自己的存储库,该存储库具有所需的接口,以便通过另一个聚合根获取项目集合。如:

public interface IStockRepository
{
    IEnumerable<StockItem> FetchByProduct(Product product);
    // ...
}

领域驱动设计——大型子集合

这个"我想保持从聚合根导航到这些大型集合的能力"…是一种气味。如果你不介意我这么说的话,你似乎很痴迷于你的聚合体的结构,而不是它的行为,它正在解决什么问题,任何起作用的不变量。坦白说,你的感觉是错位的。这是我们结构化的、面向数据库的思维方式的残余。

总的来说,我想说,首先不应该有这么大的集合。首先,加载它们需要的资源(内存、cpu、带宽)最好花在其他地方。从更实用的角度来看,人们往往不会一次处理大量的事情,甚至当你把事情分解成工作单元时,计算机也可以做更多的工作。因此,尽量远离大型集合,并总是问"为什么"你首先需要它们。

公告可以是其自身的聚合,通过其id引用员工,因此我们知道该公告是关于谁的(或针对谁的?)如果公告针对的是一组员工,那么您可能希望查看是什么定义了该组,并对其进行显式建模。直接消息也可以是它自己的聚合,因为它可能是从一个人到另一个人的消息。可以说员工的角色是消息接收者和/或发送者。同样,按id引用员工聚合就足够了。一个库存项目可以单独处理,并通过其productid引用它在库存中表示的产品。一个员工的行为是什么,一个公告,一个直接的消息,一个产品,一个库存?改变合作者的状态是如何以及何时影响他们的,为什么会这样?这是解决根本问题的方法。找到它。

总而言之,有时候你可以稍微改变一下规则,但这种情况应该很少。

看看Vaughn Vernon的论坛DDD示例。他根据聚合根对大型集合进行建模。创建是通过工厂方法在聚合上完成的,以保持对某些事情的控制,例如在论坛关闭时无法创建讨论。行动是通过AR论坛(如startDiscussion和moderatePost)完成的。

该方法返回一个实体(Post),该实体需要由应用程序服务保存在单独的存储库(PostRepository)中。现在您可以拥有大型集合,而无需每次都加载。

https://github.com/VaughnVernon/IDDD_Samples/tree/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/domain/model/forum