应用服务是否应该注入领域服务

Should An Application Service Be Injected Into A Domain Service

我正在使用具有以下层的 Entity Framework 6 开发 WinForms 应用程序:

当用户点击UI中的保存按钮时,会调用应用层的应用服务,并传入请求。然后,应用程序服务使用请求调用域服务。域服务调用域模型中的多个实体来对请求中使用的数据执行验证。

域模型中的一个或多个验证需要来自存储库的信息,以确定从表示层收到的请求中的数据是否符合某些业务规则。

我正在考虑两种方案来解决这个问题。

  1. 让应用程序服务从中检索所需的信息 用于验证的存储库并将这些值传递到 将调用领域模型和实体的领域服务 验证规则和值的传入请求。然后让 应用服务在域服务完成时保存请求 完成其验证,这将导致 returning 控制 回到同步等待的应用服务 完成验证。如果我这样做,那么域层将 没有对存储库的直接或间接(注入)引用。 如果我这样做,域服务的单元测试会更容易 因为没有注入任何东西来执行验证。 它需要的一切都已经传入了。缺点是有些 业务知识被放入应用程序服务中,因为现在 它需要知道要检索哪个存储库信息 验证请求。

  2. 调用域服务验证请求时, 向其中注入一个应用服务实例。领域 然后服务可以使用 注入的应用服务,其服务契约定义在 域层。一旦所有信息可用,它就会通过 根据不同实体的需要来验证规则和值。一次 验证完成后,域服务使用以下方式保存请求 注入的应用服务。当域服务完成时 并退出,它 returns 保存操作的状态到 等待验证的应用服务 完全的。然后外部等待应用程序服务可以 return 结果保存到UI。我在这里担心的一个问题是,当 对域服务进行单元测试我将不得不模拟注入的 应用服务.

哪个选项或其他行动方案会更好?提前致谢。

"Should An Application Service Be Injected Into A Domain Service"

不,从来没有!

从应用服务解析数据传给领域服务通常是没问题的,但是如果你认为领域逻辑泄露了那么 您可以应用接口隔离原则 (ISP) 并根据查询 "wanted data" 所需的合同在域中定义接口。在您的存储库或可以完成任务的任何其他对象上实现该接口并将其注入您的域服务。

例如(伪代码)

//domain

public interface WantedDataProvider {
    public WantedData findWantedData(...) {}
}

public class SomeDomainService {
    WantedDataProvider wantedDataProvider;
}

//infrastructure

public class SomeRepository implements WantedDataProvider {
    public WantedData findWantedData(...) {
        //implementation
    }
}

编辑:

I have a request aggregate root with an employee name. One rule is the employee must be full time and not a contractor

如果执行验证的信息已经存在于聚合中,您也可以将此 AR 用作其他 AR 的工厂。假设员工持有其合同类型...

Employee employee = employeeRepository.findById(employeeId);
Request request = employee.submitRequest(requestDetails); //throws if not full time
requestRepository.add(request);

请注意,这里只能使不变量最终一致,除非你改变你的聚合边界,但它与其他解决方案相同。

When a significant process or transformation in the domain is not a natural responsibility of an Entity or Value Object, add an operation to the model as a standalone interface declared as a Service. Define the interface in terms of the language of the model and make sure the operation name is part of the Ubiquitous Language. Make the Service stateless - Evans, the Blue Book

Don't lean to heavily toward modelling a domain concept as a Service. Do so only if the circumstances fit. If we aren't careful,, we might start to treat Services as our modelling "silver bullet". Using Services overzealously will usually result in the negative consequences of creating an Anemnic Domain Model, where all the domain logic resides in Services. - Vernon, the Red Book

我试图通过大量引用来说明的是,您似乎将域服务视为您必须拥有的东西,而您绝对不必这样做。您的应用程序服务可以愉快地使用存储库来获取聚合,然后调用聚合根方法来执行必要的操作。您的聚合根负责通过在其中执行必要的验证来保护自己的不变量,并在出现任何问题时抛出验证异常。

如果你绝对必须使用域服务,如果你做对了,这意味着你实现了洋葱架构,其中内层不知道外层,你的域服务将无法知道应用服务。但是,如果绝对必要,您可以将委托发送到域服务中以执行应用程序服务所需的操作。然而,这种情况太复杂了,不可能是真的。看到你只需要验证,请阅读蓝皮书和红皮书的引用部分并做出正确的决定。同样,DDD 中没有强制域服务,这是常见的误解之一。