管理实体的历史对象

g.f*_*ley 5 design-patterns domain-driven-design aggregate

我们正在将现有系统转换为 DDD,并且正在努力理解一些概念。

我们有一个名为 的聚合根,它具有和 等Animal属性。目前数据库有两个表,分别称为和,它们存储状态更改时有关动物的信息。这些表有时会删除记录,并且在从.StatusSourceStatusHistorySourceHistoryAnimalAnimalRepository

所以最大的问题是它们属于哪里?以下是我们的一些想法:

  • 将它们作为不同的实体对象作为动物聚合的一部分。并具有允许更新它们的相应方法,例如:Animal.UpdateStatus(newStatus),这将使用对象添加到集合中new StatusHistory(this)。但如上所述,当为存储库获取现有动物时,很少需要这些,因此我们不希望存储库加载它们。我们目前没有使用 ORM,而是使用存储库内的表数据网关手动映射。

  • 使每个历史实体成为聚合根。我们不喜欢这种做法,因为感觉我们并没有真正对领域进行建模,而只是朝着Active Record Pattern. 此外,为动物更新这些的任务必须位于动物实体之外。

  • 我们可以尝试将这些历史组合成另一个聚合根,称为AnimalHistory其全部目的是维持动物的历史。但这又会改变将历史存储到动物以外的其他事物中的逻辑。可能是像这样的服务AnimalProcessingService,感觉我们可能正在走向贫血的设计。

我希望有另一种选择可以为我们提供更简洁的设计。

Jer*_*eir 2

这是 Martin Fowler 最近发表的一篇有趣的文章,可能会解决您对检索中不需要某些内容(称为命令查询职责分离)的一些担忧。基本概念是您可以使用与“命令”(保存)不同的“模型”进行“查询”(读取)。

http://martinfowler.com/bliki/CQRS.html

仅仅因为您正在执行 DDD 并不意味着所有内容都需要包含在正确的域对象中。设计您的领域同样涉及服务和事件等的设计。我的意思是,通过关注“领域”需要什么以及满足这些要求的解决方案,让您的领域更自然地出现。DDD 没有严格的方法论,它更多的是一种观点选择,而不是正式的设计模式。因此,如果历史对象仅真正用于保存,那么将它们作为实体根不一定是坏事。让与“命令”相关的服务构成拯救动物和历史的正确逻辑流程。

我还想指出,像这样的东西Animal.UpdateStatus(newStatus)非常类似于 Active Record,您似乎想避免这种情况。