Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 管理实体的历史对象_Design Patterns_Domain Driven Design_Aggregate - Fatal编程技术网

Design patterns 管理实体的历史对象

Design patterns 管理实体的历史对象,design-patterns,domain-driven-design,aggregate,Design Patterns,Domain Driven Design,Aggregate,我们正在将现有的系统转换为DDD,并且正在努力围绕一些概念进行思考 我们有一个名为Animal的聚合根,它具有Status和Source等属性。目前,该数据库有两个名为StatusHistory和SourceHistory的表,用于存储状态更改时有关动物的信息。这些表有时会删除记录,从AnimalRepository获取Animal时很少需要检索记录 所以最大的问题是它们属于哪里?以下是我们的几个想法: 将它们作为不同的实体对象作为动物集合的一部分。并且有相应的方法允许更新它们,例如:Anim

我们正在将现有的系统转换为DDD,并且正在努力围绕一些概念进行思考

我们有一个名为
Animal
的聚合根,它具有
Status
Source
等属性。目前,该数据库有两个名为
StatusHistory
SourceHistory
的表,用于存储状态更改时有关动物的信息。这些表有时会删除记录,从
AnimalRepository
获取
Animal
时很少需要检索记录

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

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

  • 使每个历史实体成为聚合根。我们不喜欢这个,因为我们觉得我们并不是在真正地对领域建模,而是在向
    活动记录模式
    漂移。此外,为动物更新这些信息的任务必须位于动物实体之外

  • 我们可以尝试将这些历史合并到另一个名为
    AnimalHistory
    的聚合根中,其全部目的是维护动物的历史。但同样,这将是一种逻辑,将历史存储到动物以外的东西中。可能是像
    AnimalProcessingService
    这样的服务,这让人感觉我们可能正朝着一个贫血的设计前进


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

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

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


我还想指出,像
Animal.UpdateStatus(newStatus)
这样的东西是非常活跃的记录,这似乎是你想要避免的

如果您使用的是Ejb3,那么您可以为不同的侦听器编写自定义实现,如@PostInsert@positionpdate等事件

在这些侦听器中提供您的实现。例如,假设Animal中有更新,那么将调用您的PostUpdate侦听器,它将更新历史记录

这种方法有一个很大的优点,因为所有事情都发生在一个事务中,一旦编写了通用代码,就不必费心更新历史记录表

第二种方法是使用反射+拦截器