DDD域服务:服务类应该包含什么?

时间:2013-07-19 12:20:24

标签: domain-driven-design ddd-service

在域驱动设计中,域服务应包含自然不属于实体的操作。

我有习惯为每个实体创建一个服务并将其中的一些方法分组(Organization实体和OrganizationService服务。)

但我想的越多:OrganizationService并不意味着什么,“组织”是服务,这是一件事。

所以现在我必须添加一个组织深层复制功能,它将复制整个组织聚合,所以我想把它放在一个服务中。

我应该这样做:OrganizationService::copyOrganization(o)

或者我应该这样做:OrganizationCopyService::copyOrganization(o)

更一般地说:是一个“服务”,一个包含多个操作的抽象概念,还是一个具体操作的服务?

编辑:给出第一个不太好的例子:

  • StrategyService::apply()/cancel()StrategyApplicationService::apply()/cancel()? (此处“应用程序”与应用程序层无关;)
  • CarService::wash()CarWashingService::wash()

在所有这些示例中,最具体的服务名称似乎是最合适的。毕竟,在现实生活中,“洗车服务”是有道理的。但我最终可能会得到很多服务......

*注意:这不是关于意见的问题!这是关于领域驱动设计方法的精确,可回答的问题。在问“我应该”时,我总是厌倦亲密的选票,但 DDD的做事方式。*

2 个答案:

答案 0 :(得分:4)

我认为域服务只有一种方法是好的。但我不认为这是一个规则,就像你不能在域服务或其他东西上有多个方法。如果界面只抽象一件事或一件事,那肯定很容易保持,但域服务的粒度完全取决于你的有界上下文。有时我们过分关注低耦合而忽略了高度凝聚力。

答案 1 :(得分:1)

这有点基于意见,我想将其添加为评论但是用完了空间。

相信在这种情况下,将方法分组为一个单独的OrganizationFactory-service并使用不同的构造方法是有意义的。

   interface OrganizationFactory{
       Organization createOrganization();
       Organization createOrganizationCopy(Organization organization);
   }

我认为它将符合信息专家模式和 DRY 原则 - 一个类具有关于特定对象创建的所有信息,我不会看到任何在不同地方重复这种逻辑的理由。

然而,有趣的是在工厂模式的ddd定义中

  

转移创建复杂对象实例的责任   聚集到一个单独的对象,它本身可能没有   域模型中的责任,但仍然是域的一部分   设计。提供封装所有复杂程序集的接口   并且这不要求客户引用具体类   正在实例化的对象。

单词" object"在一般意义上,它甚至不必是一个单独的,但也可以是一个工厂方法(我的意思是类的方法和模式工厂方法) - 后来Evans给出了Brokerage Account的工厂方法示例,它创建了Trade Order的实例。

这本书引用了GoF工厂模式的家族,我不认为有一种特殊的DDD工厂分解方式 - 要点是创建的对象不是半生不熟的,工厂方法应该是添加尽可能少的依赖。

更新 DDD没有附加到任何特定的编程范例,而问题是关于面向对象的分解,所以我再也不认为DDD可以提供有关每个对象的方法数量的任何特殊建议。

有些人使用strange rules of thumb,但我相信您可以使用High Cohesion principle并将具有高度相关责任的方法放在一起。由于这是一个DDD问题,所以我认为它涉及域服务(即非基础设施服务)。我认为应该根据他们在域中的职责来划分服务。

更新2 无论如何CarService可以执行CarService::wash() / CarService::repaint() / CarService::diagnoseAirConditioningProblems(),但CarWashingService会做的很奇怪CarWashingService::diagnoseAirConditioningProblems()就像乔姆斯基的生成语法一样 - 语言中的一些陈述(句子)是有道理的,有些不是。但是,如果你的句子包含太多的主语(超过5-7),那么即使它是有效的语言句子,也很难理解。