【发布时间】:2019-04-06 13:39:07
【问题描述】:
假设我不想更新 Person 实体的昵称,并规定此昵称最多可供 5 个其他人使用。我该怎么做?
在调用更新之前,我应该在域服务中进行验证吗?
或者将 personRepository 传递给 PersonEntity.update(...) 方法,并在实体更新方法中进行搜索和验证是否更好?
补充说明:
@plalx 创建附加实体来执行此规则的想法很聪明。
当我阅读 DDD 时,我经常读到不推荐将存储库传递给实体(如果不是邪恶的话)。这就是为什么我试图找到一个我们需要存储库或实体中的其他服务的示例)。我实际上不知道是否仅传递存储库是不好的并且服务是好的,或者同样不鼓励将服务传递给实体。
让我们假设这条规则不是那么难和重要的业务规则,并且我们可以有多个类似的规则(如此之多,为我们要验证的每个属性创建一个附加实体有点过度设计)。假设我们可以在并发更新的情况下允许 6 或 7 个相同的昵称(我们只想将它们限制在相当小的数量)并检查
personRepository.usageOfNickname(this/person.nickname) < 5
就足够了。在这种情况下,从 DDD 的角度来看,哪种设计更好?
-
将 personRepository 传递给 Person 实体
class Person { ... boolean changeNickname(newNickname, nicknameUsageService) { if (personRepository.usageOfNickname(this.nickname) < 5) { this.nickname = newNickname; return true; } else { return false; //or throw } } }这对我来说似乎是最明显和最直接的,好处是逻辑包含在实体中,但困扰我的是这种将存储库传递到实体的可悲传递以及这种感觉埃文斯不鼓励这样做
不是将 personRepository 传递给 Person Entity,而是将 personService 传递给 Person Entity(类似于 @plalx 的示例)——将服务传递给 Entity 比存储库更好吗?
- 在服务中进行验证类似于@plalx 示例
changePersonNickname(personId, newNickname){...}但在@plalx 的示例中使用服务似乎是合理的,因为它在两个实体上运行,这里我们只有一个实体,如果把这个逻辑放在它担心服务而不是实体中的服务不会转向贫血域模型并离开 DDD。
【问题讨论】:
-
注入服务的缺点是它使测试更加乏味(需要更多的模拟/存根)。您不通过整个存储库的原因是尊重接口隔离原则 (ISP);支持特定于任务的接口(例如
NicknameUsageProvider,可以由存储库类实现)。最后,您还可以在应用服务中获取数据并将其传递给 AR 的方法。nicknameUsage = …; person.changeNickname(newNickname, nicknameUsage).
标签: oop domain-driven-design repository-pattern ddd-repositories aggregateroot