在另一个内部使用一个存储库

时间:2016-04-12 13:49:09

标签: design-patterns domain-driven-design repository-pattern

我是DDD新手,我有一个合作伙伴聚合,有一个用户参考。 User对象本身是另一个Aggregate。

由于并非所有用户都必须在Partner对象中引用,因此User对象是聚合根。 合作伙伴也是聚合根。

第一: 我的设计在另一个聚合根中是否会出错?

第二: 如果设计是正确的,那么在另一个内部使用一个存储库来持久化合作伙伴是不是一种坏习惯? (PartnerRepository内的UserRepository)

Obs:我没有使用任何ORM框架。

3 个答案:

答案 0 :(得分:3)

  

我是DDD新手......

我将从DDD角度回答这个问题,而不是OOP(面向对象编程)。

  

首先:我的设计是否错误,内部有一个聚合根   另一?

它不符合域驱动设计的一般准则。如果要从另一个引用一个聚合根,则可以通过id引用它。

  

第二:如果设计是正确的,那么使用它是不好的做法   在另一个内部的存储库来持久化合作伙伴? (UserRepository   在PartnerRepository中)

如果遵循DDD的指导原则,您不会这样做,您将使用单独的存储库单独保留每个聚合。

Here's a link to an article by Vaughn Vernon,可能是DDD领域的第二大人物,可以更好地解释。

答案 1 :(得分:2)

  

首先:我的设计是否会在另一个聚合根中出错?

  

<强> AGGREGATE   一组关联对象,它们被视为一个单元,用于更改数据。外部引用仅限于聚合的一个成员,指定为根。一组一致性规则适用于聚合的边界。

Eric Evans, Domain Driven Design

您的设计面临的问题是:如果允许用户聚合独立修改相同的状态,则合作伙伴聚合无法保护其自身的不变量。

在您的设计中,当您断言X是聚合时,您正在提出两项索赔

  1. 可以在不咨询任何外部状态的情况下确定对X的任何更改的有效性。
  2. 可以在不咨询X状态的情况下确定任何外部变更的有效性。
  3. 这是总的边界 - 外面的变化不需要向内看,内部的变化不需要向外看。

    因此,嵌套聚合是一个矛盾。

    表达相同想法的另一种方式:如果一个聚合根位于另一个聚合根内,那么您将拥有一个聚合(合作伙伴聚合),其具有两个根(合作伙伴实体和用户实体) ,这正是聚合模式旨在避免的情况。

    可能的补救措施:

    一个是用户实体确实是合作伙伴聚合的一部分。对用户的每次更改都应由合作伙伴管理。您将用户移回合作伙伴聚合,并阻止您的实现访问它,除非通过向聚合根发出命令。

    另一个是用户实体不是合作伙伴聚合的一部分。然后你消除了合作伙伴中的直接引用;这可能意味着完全取消引用(如果合作伙伴的业务规则完全不依赖于用户),或者引用用户标识符,以及检查标识符而没有的业务规则跟随它(换句话说,您的规则可能会检查id引用是null / not null,还是/不是集合的成员)。如果您考虑一下,合作伙伴汇总甚至无法判断其引用的用户是否存在

    第三种是在模型中发现新实体,其中包括合作伙伴聚合实际用于验证的用户部分。这可能是用户状态的快照,也可能是用户重构为多个部分。

答案 2 :(得分:-2)

  

首先:我的设计是否错误,内部有一个聚合根   另一?

我对此表示怀疑。例如,User可以是某个域的聚合根,称为用户管理UserProfile是其他域的聚合根,称为用户配置文件,并且两个域对象之间可能存在1:1关联。

  

第二:如果设计是正确的,那么使用它是不好的做法   在另一个内部的存储库来持久化合作伙伴? (UserRepository   在PartnerRepository中)

您应该确保明确区分问题并遵循单一责任原则。也就是说,存储库可以处理单个域对象,并且在另一个域内注入存储库可以打开处理相关或不相关的域对象的大门。

我的建议是,您应该代表域名服务中的交易,并且您可以根据需要注入尽可能多的存储库。