那么我的应用程序遵循 DDD 设计原则。它是一个 ASP.NET MVC 应用程序,其中 MVC Web 应用程序是表示层(尽管我将 Controller 移到了应用程序层)。它还具有应用层,主要是应用服务、用例等。应用层之上是领域模型所在的领域层。然后是基础设施层,它位于其他所有层之上,应该不依赖于其他层。
但是我注意到一个问题,如果持久化逻辑像 DDD 书籍所建议的那样进入基础设施层,基础设施层将依赖于域层。例如,存储库需要知道要创建的领域模型(实体)的类型,有了这些知识,它们就依赖于领域层。然而,最初的 DDD 原则表明基础设施层应该绝对不依赖任何东西。
所以现在我很困惑,持久化逻辑真的应该属于基础设施层吗?如果是这样,它会使基础设施层依赖于域层。如果不是,那么它应该在哪里?应用层?或者可能是应用程序层和领域层之间的单独层(因为应用程序服务使用存储库,存储库使用领域模型)。你怎么认为?
依赖类型
我认为在这里可能有帮助的一个重要概念是区分依赖的类型——具体来说,一个层或组件可以依赖于另一个层,因为:
根据该层中定义的概念定义,或
它使用另一层 - 通过委托(delegate)给该层(又名调用该层中的服务的方法)
或以上两者
Inversion of Control和
Dependency Injection使这种区别变得更加重要。他们指导我们应该依赖抽象而不是具体。
这意味着,例如,领域层可以定义并依赖于存储库的抽象——例如一个 IEntityRepository 接口(interface)。
然而,实现(凝结)然后在基础设施层中实现。
当应用层想要调用存储库时,它依赖于抽象(接口(interface)),控制系统(IoC 容器)的反转为其提供基础设施层的实现。
在这种情况下,基础设施层依赖于域层——但只是为了了解它正在实现的接口(interface),但它不依赖于任何其他层来委托(delegate)给它——它是调用中的最后一层堆。
这个概念解决了您所关心的冲突,因为基础设施层不依赖于其他任何东西来执行它的功能。
洋葱建筑
一旦您开始将 IoC 概念纳入对架构的思考中,一个非常有用的模型是
onion architecture图案。在这个 View 中,我们保留了分层方法,但不是将其视为一个堆栈,而是将其视为一个分层的洋葱,以域为中心,与应用程序之外的所有事物的交互在边缘。
最初的 DDD 书籍并没有特别提及这一点,但它已成为实现 DDD 系统的一种非常常见的模式。
它也被称为
Ports and Adaptor模式,或
Hexagonal Architecture .
这个想法是,它根据洋葱的“知道”来建模依赖关系——外层知道内层,但内层不知道外层。
但它根据跨洋葱的移动来模拟应用程序流的委托(delegate)——从洋葱的一侧到另一侧。
更具体:
外层(也称为“主要适配器”)是请求进入系统的地方。适配器负责处理特定的 API 表示(例如 REST api)并将其转换为对应用程序服务层的请求 - 下一层。这通常表示为洋葱的左上角。
应用服务层代表应用的“用例”。通常,方法将使用存储库接口(interface)来检索聚合的实例,然后委托(delegate)给聚合根上的方法来执行涉及根据用例的需要更改聚合状态的业务逻辑。应用服务层,然后使用另一个接口(interface)要求基础设施层“保存”更改(通常使用工作单元抽象)
在这里,我们有应用层将控制流委托(delegate)给洋葱的“外层”(也称为“辅助适配器”)。这通常表示为洋葱的右下角,类似于您描述中的“基础设施层”。
这就是 IoC 的用武之地。 因为我们有一个内层委托(delegate)给外层,所以才有可能,因为外层已经实现了一个定义在内层中的接口(interface)(它可以这样做,因为它知道内层) .然而,IoC 容器注入(inject)了实际的具体实现,这有效地允许内层将控制委托(delegate)给外层而不依赖于它。
在这个概念中,请求从左上角流到右下角,而内层不知道外层的任何信息。
我是一名优秀的程序员,十分优秀!