【发布时间】:2015-03-02 12:32:31
【问题描述】:
我想问一下我在游戏实现中使用 DDD 时遇到的问题。
我有一种情况,根据系统收到的消息,为玩家创建了一个新的聚合。问题来自于这个新聚合必须由另一个聚合(表聚合)使用其 id 引用。第二个聚合保留了一个值对象,其中包含有关牌桌上玩家的信息,例如他的位置或选择的颜色。玩家聚合存储玩家动作,因为根据玩家的数量和他们发出的动作,表聚合可能会变得庞大,如果我将所有内容都保留在表上,数据库中的锁争用成本会太高。为了让玩家能够加入表格,必须首先通过一些验证,例如未采用颜色、已达到最大玩家数量或玩家已处于非活动状态的游戏,这就是为什么此值对象与信息一起存储在表格中的原因来自玩家。
因此,基于此,我仅在玩家发出要存储在表外的第一个动作时才创建玩家聚合。这样做的问题是该表可能包含引用尚未创建的聚合的值对象,这使得代码看起来很难看,因为它迫使它检查空引用。另一种选择,即首先创建玩家集合,也破坏了设计,因为创建玩家的验证首先发生在桌子上。由于系统的并发性,首先在表上进行验证,然后创建玩家集合,然后在接收到来自创建的事件时更新表,这可能会导致许多竞争条件。我唯一能想到的是在同一个事务中更新两个聚合,但这违反了 DDD 规则。
有什么好的解决办法吗?我想这最终将与设计有关,但我想不出任何方法可以在不引入性能问题的情况下工作。
谢谢。
【问题讨论】:
-
player = table.newPlayer(...); playerRepository.save(player); tableRepository.save(table);之类的东西呢,Table只是将 VO 添加到内部集合中。在这里,您不要在同一个事务中修改两个聚合,因为播放器是刚刚创建的,而不是修改的。因此,播放器实例上不能存在争用。 -
你真的能做到吗?我认为不修改同一事务中的两个聚合的全部内容也包括创建。即使这在我的情况下也行不通,因为一旦离开表格,玩家就不会从 PlayerRepository 中删除。我必须检查是否这样做,我不知道我是否会破坏其他东西。还有另一个要求为玩家存储快捷方式,但这可能在另一个有界上下文中,因此在玩家离开后移除玩家仍然是安全的。但我想先知道在 ddd 中是否同时更新和创建有效。
-
是的,我相信它是有效的,因为不会增加并发冲突的风险。例如。无论您只修改
Table聚合还是修改Table聚合并创建Player对象并保存它,都不会在并发冲突方面发生任何变化。并发冲突是避免在单个事务中修改多个聚合的主要原因。 -
感谢您的提示,真正理解 DDD 以及什么是允许的,什么是不允许的并不是一个容易的主题。