我们想要为仓库应用程序建模。让我们假设我们确定了以下现实世界的对象:
存在以下限制:
首先我们有一个操作:
当然这很简单。
应该如何建模呢?
Stockitem可能是我认为的价值对象。一种解决方案是将整个仓库建模为具有调色板和隔间实体的聚合。在这种情况下,关于其约束(不变量),可以实现移动操作而没有任何问题。但这种方法有明显的缺点。此聚合的事件日志将无限增长。由于聚合版本控制等原因,无法并行执行两个移动操作。从ddd的角度来看,感觉不适合我。
另一种方法是使每个调色板和每个隔间都有自己的聚合。但是,如何实施移动操作呢?
问题1:谁加载了引用的聚合?
我认为它应该坚持调色板。调色板可以引用它所在的隔间(它是一个聚合体)。但是这个参考是如何实现的(CQRS / ES)?移动命令的Comandhandler显然将从调色板存储库加载调色板聚合并在其上调用move方法。谁加载引用的隔间?谁加载隔间应该移动到?我读到聚合不应该访问存储库。命令处理程序是否应加载两个隔离专区?隔间是否应该作为参数给予移动方法?或者命令处理程序是否应将当前隔离专区设置为调色板并将目标隔离专区作为参数?
问题2& 3:聚合之间的约束和双向关联
约束怎么样?要检查目标隔间是否为空,隔间需要知道存储在其中的调色板。这将是一个应该避免的双向关联。并且因为它们是不同的聚合,所以无法在同一事务中更新它们。是否有调色板来触发域事件以通知隔间它将移动到它?是否可以将其作为具有撤消操作的传奇来实现?如果两个动作冲突,一个人获胜,但失去的调色板无法移回,因为旧隔间在此期间被填满了怎么办?
对于这个非常简单的问题,这一切对我来说都很复杂。
在书籍和例子中,似乎都很清楚。但如果我尝试使用它,我似乎做错了。
请问有人指导我正确的方向吗?
答案 0 :(得分:1)
您应该开始对行为进行对象建模,而不要考虑聚合和值对象。一旦您对所需行为建模,您就会知道实体,聚合,根和值对象是什么。
在Vaughn Vernon的解释中,他清楚地表明,在做出这些决定之前,你需要弄清楚你需要的细节。
答案 1 :(得分:1)
问题1
我认为除了业务分析之外,您还需要进行一些事务分析。
如果您的域名具有高度协作性(建议使用DDD),那么移动到指定隔间的频率是多少?在跨越2 Compartment
聚合(源和目标)的事务下,Move操作是否可行?或者最终的一致性是否足够,源Compartment会通过Palette离开它的事件向世界发出信号,而目标Compartment会以某种方式以异步方式通知Palette正在加入它?
在一小段时间内漂浮“陷入困境”的调色板是完全可以接受的,这是你需要向领域专家询问的事情。
问题2
双向关联不是唯一的解决方案。你可以向PaletteRepository
询问所有具有CompartmentID X的Palettes。或者,Compartment可以(应该)有一个Palette ID列表,而不是对它们的完整引用。
总的来说,我认为你应首先考虑一下你所问的所有设计问题的商业含义/答案。领域专家通常会对最终的一致性是否切合实际或是否需要立即一致性,在发生冲突时应该发生什么等方面有一个受过教育的意见。