Domain driven design 公开类似于存储库的方法的域实体

Domain driven design 公开类似于存储库的方法的域实体,domain-driven-design,Domain Driven Design,就拿这个例子来说。主管域类公开了一个方法 获取下属(DateTime from,DateTime to)将返回给定时间段内由给定主管监督的所有人员 出于令人愉快的语义原因,该方法应该放在这里。但是为了DDD纯度应该去别的地方。这是因为我假设要实现需要使用存储库的方法,而将存储库嵌入域实体中似乎是错误的。在这种情况下,该方法应该进行响应或服务-GetUnderlines(主管-主管,DateTime-from,DateTime-to) 其他人如何处理这种情况 编辑:我认为这些力量可以这样描述:根据

就拿这个例子来说。主管域类公开了一个方法 获取下属(DateTime from,DateTime to)将返回给定时间段内由给定主管监督的所有人员

出于令人愉快的语义原因,该方法应该放在这里。但是为了DDD纯度应该去别的地方。这是因为我假设要实现需要使用存储库的方法,而将存储库嵌入域实体中似乎是错误的。在这种情况下,该方法应该进行响应或服务-GetUnderlines(主管-主管,DateTime-from,DateTime-to)

其他人如何处理这种情况

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

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

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

  • 如果
    Supervisor
    是一个
    Aggregate Root
    ,则可以从
    Supervisor
    返回
    下属
    列表,但只需只读集合即可,因为
    下属
    应该由
    Supervisor
    修改,以将域规则和不变量应用于修改操作。(基本规则不仅适用于DDD,也适用于OOP设计)

    下属
    看起来像一个历史
    实体
    。在大多数情况下(我没有足够的上下文信息来证实您的情况),历史
    实体
    不是
    聚合根
    ,只有
    聚合根
    有存储库


    请记住,如果
    取消绑定的检索是针对
    UI
    (不应用带有规则和不变量的操作),那么您不需要关心
    聚合根
    实体
    ,等等,因为您应该应用CQR并使用view services来检索普通数据(第一个标准形式,不是
    聚合根
    )向用户显示。当用户
    UI
    触发操作时,您需要检查规则(即应用DDD);您从
    存储库
    检索
    主管
    ,检查
    下划线
    (请记住,只读集合)要做出决定,请应用操作并保存更改。

    一种常见的方法是将所有
    主管的
    下属作为只读集合公开。如果需要实现一种按日期范围过滤的方法,只需将此方法添加到类
    主管
    作为
    获取下属即可(DateTime from,DateTime to)
    一切正常

    如果通用方法不起作用,因为您的
    主管
    有大量的
    下属
    ,或者检索所有这些
    下属
    ,非常耗时,或者……Martin Fowler提出了一种变通方法-“(PoEAA)模式

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

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


    如果基础数据属于管理者集合,则管理者应拥有这些数据的集合

    班主任{
    私人藏品;
    }
    
    然后getUnderlines(DateTime from,DateTime to)过滤未解析项。这很好

    但是,如果有太多属于主管的底层,则此解决方案对性能不友好。在这种情况下,我希望使用使底层成为聚合根并使用其存储库检索结果,如:

    interface UnderlyingRepository {
          Collection<Underlying> GetUnderlings(Guid supervisorId, DateTime from, DateTime to);
    }
    
    接口基础存储库{
    集合getUnderlines(Guid supervisorId、DateTime from、DateTime to);
    }
    
    客户机(可能是MVC控制器)直接调用存储库,然后问题是如何保护以前由Supervisor聚合保护的AddUnderground的不变量。 您可以使用DomainService或DomainEvents


    上面的解决方案基于传统的DDD架构模型。正如@jlvaquero所说,您可以使用CQRS。

    在这种情况下,我也会使用
    Service.getUnderlines(…)
    。让我们等待有人写一个更深入的回复。但这仍然意味着域实体有一个对“服务”的引用接口。这实际上是我问题的关键。实体是否应该引用这样的服务(即使只是一个接口)我已经编辑了我的帖子,并指定它只能在“通用方法不起作用”时使用。首先,你应该尝试实现更简单、更可取的通用方法,然后寻找解决方法。谢谢。事实上,据我所知,你的观点并不完全正确。聚合实体中的项只能通过聚合根访问(不是通过任何其他机制)。这与一个实体不应引用不在同一聚合中的其他实体完全不同。实体可以相互关联,但不在同一聚合中。
    interface UnderlyingRepository {
          Collection<Underlying> GetUnderlings(Guid supervisorId, DateTime from, DateTime to);
    }