我正在学习 DDD 概念并加强我的理解,我正在研究一些现实世界的例子。
我知道聚合应该只有一个通过根实体的入口点,聚合应该只有一个存储库(如果我完全理解错误,请纠正我)
现在假设有特定类型的消耗品,这些消耗品是从配送中心发送的。发送特定类型的消耗品取决于它们的数量,我的意思是,如果其中一位消费者的 A 型和 B 型的评论数量为 10,并且这些物品数量低于 10,那么配送中心会发送 A 型和 B 型消耗品。在这里,发送者和消费者都想跟踪发送的包裹在哪里,或者它是否已经交付或发送。
所以在这里,作为实体,我们有:
- 消耗品
- 消耗品类型
- ConsumableActivity
- 包裹
- 包裹物品
- 消费者
我对前三个实体感到困惑:哪个应该是聚合根?乍一看,消耗品似乎是一个强有力的候选者,但另一方面,我们并不关心每一个消耗品,我们只对它们的数量感兴趣。我们没有记录 10 种不同的 A 类消耗品,而只有一个 A 类记录,其数量根据活动而变化。在这一点上,Consumable 实体似乎是多余的,仅通过查看活动我们就可以得出数量。例如从头开始:
- 中心创造“A型”10
- 中心创造“B型”20
- 中心发送“Type A” 5 ConsumerId=25
- 中心发送“Type B”15 ConsumerId=25
- ConsumerId=25 接收“A 型” 5
- ConsumerId=25 接收“B型” 15
- ConsumerId=25 消费“A 型” 3
- ConsumerId=25 消费“B型”1
- ConsumerId=25 消费“A 型”2
在这里,我们可以得出,中心有 5 个 A 型和 B 型消耗品,而现在 id 为 25 的消费者有 0 个 A 型和 14 种 B 型消耗品。
当然这不是一个有效的方法,因为在有更多的活动之后,需要一些时间来得出消耗品的数量,因此对于消费者和配送中心的每种消耗品类型都应该有一个静态数量字段,我们可以在其中阅读当前数量一次。
我希望你明白我为什么感到困惑,消耗品实体看起来像一个根实体,但实际上它并不适合成为一个根实体,如果它也不是一个实体的话。
谁能建议我对此设计进行一些改进或进一步阅读建议,这些建议不仅限于客户-产品-订单-订单的噩梦吗?
编辑:与 Consumable 和 ConsumableType 有什么关系?如果我想对 ConsumableType 进行 CRUD 操作(让用户添加新类型、更改或删除它们)但根实体是 Consumable 怎么办。为了 DDD 保持数据完整性,我们不应该加载根实体存储库以外的任何存储库。
编辑 2:考虑 Product 实体及其 Category 实体。产品似乎是根实体,但我们知道产品不能没有类别而存在。那么类别实体是根吗?如果是这样,根据 DDD 规则,我们只能通过遍历来访问产品。但在我们的上下文中,产品是我们关注的焦点。然后假设我们有两个聚合:Product Aggregate 和 Category Aggregate。但是这次我们违反了数据完整性,因为可以删除一个类别而不删除具有该类别的产品。所以我很困惑,找不到合适的解决方案。