1

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

  • 介绍
  • 应用
  • 领域
  • 基础设施

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

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

我正在考虑两种选择来解决这个问题。

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

  2. 在调用域服务以验证请求时,将应用程序服务的实例注入其中。然后,域服务可以使用注入的应用程序服务从存储库中获取信息,其服务合同在域层中定义。一旦所有信息都可用,它会根据需要传递给各种实体以验证规则和值。验证完成后,域服务使用注入的应用程序服务保存请求。当域服务完成并退出时,它会将保存操作的状态返回给一直在等待验证完成的应用程序服务。外部等待的应用程序服务然后可以将保存的结果返回给 UI。

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

4

2 回答 2

5

“是否应该将应用服务注入到域服务中”

没有永不!

解析来自应用程序服务的数据并将其传递给域服务通常很好,但如果您认为域逻辑正在泄漏,那么您可以应用接口隔离原则(ISP)并根据合约在域中定义一个接口需要查询“想要的数据”。在您的存储库或任何其他可以完成任务并将其注入您的域服务的对象上实现该接口。

例如(伪代码)

//domain

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

public class SomeDomainService {
    WantedDataProvider wantedDataProvider;
}

//infrastructure

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

编辑:

我有一个带有员工姓名的请求聚合根。一条规则是员工必须是全职而不是承包商

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

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

请注意,除非您更改聚合边界,否则此处只能使不变量最终保持一致,但这与其他解决方案相同。

于 2016-02-20T17:20:52.900 回答
2

当域中的重要过程或转换不是实体或值对象的自然责任时,将操作添加到模型中作为声明为服务的独立接口。根据模型的语言定义接口,并确保操作名称是通用语言的一部分。使服务无状态 - Evans,蓝皮书

不要过于倾向于将领域概念建模为服务。只有在情况合适的情况下才这样做。如果我们不小心,我们可能会开始将服务视为我们的建模“银弹”。过度使用服务通常会导致创建记忆缺失域模型的负面后果,其中所有域逻辑都驻留在服务中。- 弗农,红皮书

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

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

于 2016-02-20T21:38:22.080 回答