【问题标题】:A domain entity exposing a repository-like method公开类似存储库的方法的域实体
【发布时间】:2013-10-27 00:32:44
【问题描述】:

举个例子。 Supervisor 域类公开一个方法 GetUnderlings(DateTime from, DateTime to) 将返回给定时间段内由给定主管监督的所有人员。

出于令人愉悦的语义原因,该方法应放在此处。但是应该去其他地方以获得 DDD 纯度。那是因为我假设实现需要使用存储库的方法,将其嵌入域实体中似乎是错误的。在这种情况下,该方法应该在 Respository 或 Service 上运行 - GetUnderlings(Supervisor supervisor, DateTime from, DateTime to)

其他人如何处理这种情况?

编辑:我认为这些力量可以这样描述:根据 OO 原则,我希望我的实体的公共接口能够公开一组丰富的面向业务的功能。但是根据 DDD 实现原则,这些方法的实现可能最好位于其他地方。例如,在服务中。

如何解决这种明显的冲突?我可以看到的方式是:

  1. 让实体引用服务或服务接口
  2. 始终让客户端访问服务,而不是直接访问实体(结果:失去一致性,从 OO 的角度来看完全不酷)
  3. 使用“域事件”(?)
  4. 使用一些 AOP 技巧将方法的实现委托给服务。

【问题讨论】:

  • 我也会在这种情况下使用Service.GetUnderlings(...)。让我们等待有人写更深入的回复。

标签: domain-driven-design


【解决方案1】:

如果SupervisorAggregate Root,则从Supervisor 返回Underlings 列表是有效的,但只是READONLY 集合,因为Underlings 应由Supervisor 修改以应用域修改操作的规则和不变量。 (基本规则不仅在 DDD 中,也是很好的 OOP 设计)

Underlings 似乎是一段历史entity。在大多数情况下(我没有足够的上下文信息来确认你的情况)历史 entities 不是 aggregate roots 并且 ONLY aggregate roots 有存储库。

请记住,如果 Undelings 的检索是针对 UI 的(不是应用具有规则和不变量的操作),您不需要关心 aggregate rootsentities 等,因为您应该应用 CQRS 并使用视图服务来检索纯数据(第一范式,而不是 aggregate roots)以将其显示给用户。当用户UI触发动作时,您需要检查规则(即应用DDD);您从Repository 中检索Supervisor,检查Underlings(记住,只读集合)以做出决定、应用操作并保存更改。

【讨论】:

  • 谢谢。实际上,在我的理解中,您的观点并不完全正确。聚合实体中的项目只能通过聚合根访问(不能通过任何其他机制)。这与说一个实体不应该给出对不在同一聚合中的其他实体的引用完全不是一回事。实体可以相关,但不能在同一个聚合中。
【解决方案2】:

一种常见的方法是将所有SupervisorUnderlings 公开为只读集合。如果您需要实现按日期范围过滤它们的方法,您只需将此方法添加到类SupervisorGetUnderlings(DateTime from, DateTime to),一切正常。

如果通用方法不起作用,因为您的 Supervisor 有很多 Underlings,或者检索所有这些 Underlings 很耗时,或者......有一个解决方法- Martin Fowler 的“Separated Interface”(PoEAA) 模式。

您可以在域模型中定义一个在特定日期范围内返回Underlings 的组件接口,但在另一层(例如数据访问层)中实现它。

在这种情况下,您的域实体没有对服务的引用,也没有公开任何“下属”。所有需要获取“Underlings”调用服务并将“Supervisor”实例传递给方法和日期范围的客户端。

【讨论】:

  • 但这仍然意味着域实体具有对“服务”接口的引用。这实际上是我问题的症结所在。实体是否应该引用此类服务​​(即使只是一个接口)
  • 我已经编辑了我的帖子并指定它只能在“常用方法不起作用”时使用。首先,您应该尝试实施更简单、更可取的通用方法,然后寻找解决方法。
【解决方案3】:

如果它们属于 Supervisor 聚合,Supervisor 应该有一个 Underlying 的集合。

喜欢

class Supervisor {
    private Collection<Underlying> underlyings;
}

然后 GetUnderlings(DateTime from, DateTime to) 正在过滤 undlyings。这很好。

但是如果有太多的底层属于一个主管,这个解决方案对性能不友好。在这种情况下,我想使用 make Underlying 聚合根并使用它的 Repository 来检索结果,例如:

interface UnderlyingRepository {
      Collection<Underlying> GetUnderlings(Guid supervisorId, DateTime from, DateTime to);
}

客户端(可能是 MVC 控制器)直接调用存储库。那么问题是如何保护 addUnderlying 的不变量,这些不变量曾经受到 Supervisor 聚合的保护。 您可以使用 DomainService 或 DomainEvents。

上述解决方案基于传统的 DDD 架构模型。就像@jlvaquero 所说,您可以改用 CQRS。

【讨论】:

    猜你喜欢
    • 2011-09-28
    • 2018-08-03
    • 1970-01-01
    • 2018-05-25
    • 2018-06-02
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多