在域驱动设计中,域服务应包含自然不属于实体的操作。
我有习惯为每个实体创建一个服务并将其中的一些方法分组(Organization
实体和OrganizationService
服务。)
但我想的越多:OrganizationService
并不意味着什么,“组织”是不服务,这是一件事。
所以现在我必须添加一个组织深层复制功能,它将复制整个组织聚合,所以我想把它放在一个服务中。
我应该这样做:OrganizationService::copyOrganization(o)
?
或者我应该这样做:OrganizationCopyService::copyOrganization(o)
?
更一般地说:是一个“服务”,一个包含多个操作的抽象概念,还是一个具体操作的服务?
编辑:给出第一个不太好的例子:
StrategyService::apply()/cancel()
或StrategyApplicationService::apply()/cancel()
? (此处“应用程序”与应用程序层无关;)CarService::wash()
或CarWashingService::wash()
?在所有这些示例中,最具体的服务名称似乎是最合适的。毕竟,在现实生活中,“洗车服务”是有道理的。但我最终可能会得到很多服务......
*注意:这不是关于意见的问题!这是关于领域驱动设计方法的精确,可回答的问题。在问“我应该”时,我总是厌倦亲密的选票,但是 DDD的做事方式。*
答案 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),那么即使它是有效的语言句子,也很难理解。