Lor*_*ill 3 c# asp.net-mvc persistence domain-driven-design repository
好吧,我的应用程序遵循DDD设计原则。它是一个ASP.NET MVC应用程序,其中MVC Web应用程序是表示层(尽管我将控制器移到了应用程序层)。它还具有主要是应用程序服务,用例等的应用程序层。在应用程序层之上是域模型所在的域层。然后是基础架构层,它位于所有其他事物之上,并且应该不依赖其他任何层。
但是我注意到一个问题,如果持久性逻辑按照DDD书籍的建议进入基础架构层,则基础架构层将依赖于域层。例如,存储库需要知道要创建的域模型(实体)的类型,并以此知识为基础来依赖域层。但是,原始DDD原则建议基础结构层绝对不应该依赖任何内容。
所以现在我很困惑,持久性逻辑是否真的应该属于基础架构层?如果是这样,它将使基础结构层依赖于域层。如果没有,那应该在哪里?应用层?或者可能是应用程序层和域层之间的一个单独的层(因为应用程序服务使用存储库,存储库使用域模型)。你怎么看?
我认为可能在这里有帮助的一个重要概念是区分依赖关系的类型-具体来说,一个层或组件可以依赖于另一个层,因为:
控制反转和依赖注入使这种区别更加重要。他们指导我们应该依靠抽象而不是凝结。
这意味着,例如,域层可以定义并依赖于存储库的抽象-例如IEntityRepository接口。
但是,该实现(创建)然后在基础结构层中实现。
当应用程序层要调用存储库时,它取决于抽象(接口),并且控制系统的反转(IoC容器)向其提供基础结构层的实现。
在这种情况下,基础设施层依赖于域层-但仅仅是为了了解它是实现接口,但它确实不是为了依赖于任何其他层上委托给它-它是在调用的最后一层堆。
这个概念解决了您担心的冲突,因为基础结构层不依赖任何其他东西来实现其功能。
一旦开始将IoC概念纳入关于架构的思考中,洋葱架构模式将成为非常有用的模型。在此视图中,我们保留了分层方法,而不是将其视为堆栈,而是将其视为分层洋葱,以Domain为中心,并与应用程序外部的所有内容进行交互。
最初的DDD书籍并未专门提及这一点,但它已成为实现DDD系统的非常普遍的模式。
这个想法是,它根据洋葱的“了解”来建模依赖关系-外层知道内层,但内层不知道外层。
但是,它根据洋葱的移动方式(从洋葱的一侧到另一侧)对应用程序流的委派进行建模。
更加具体:
外层(也称为“主适配器”)是请求进入系统的地方。适配器负责处理特定的API表示形式(例如REST api),并将其转换为对应用程序服务层(位于其中的下一层)的请求。这通常表示为洋葱的左上角。
应用程序服务层表示应用程序的“用例”。通常,一种方法将使用存储库接口来检索聚合实例,然后委托给聚合根目录上的方法以执行业务逻辑,该业务逻辑涉及按用例要求更改聚合状态。然后,应用程序服务层使用另一个接口来请求基础结构层“保存”更改(通常使用工作单元抽象)
在这里,我们有应用程序层将控制流委派给洋葱的“外层”(也称为“辅助适配器”)。这通常表示为洋葱的右下角,类似于描述中的“基础结构层”。
这就是IoC的来历。因为我们有一个委派给外层的内层,所以这仅是可能的,因为外层已经实现了在内层中定义的接口(之所以可以这样做是因为它知道内层) 。但是,IoC容器注入了实际的具体实现,从而有效地允许内层将控制权委派给外层而不依赖于它。
在此概念化中,请求从左上角流到右下角,而内层不知道有关外层的任何信息。
这里有2个选项
1) 使用 DAO 对象。那么基础设施层只需要知道那些DAO对象。特别是如果您使用实体框架或类似的框架,那么这不是一个糟糕的策略。您确实会从映射中获得一些开销,但您可以使用自动映射器来实现这一点。
2) 接受基础设施了解您的 DDD 模型这一事实。但由于 DDD 中的一切都围绕着您的领域模型,这并不是一个糟糕的权衡。(特别是如果您的领域模型很好理解,因此不会发生根本变化)。但要非常小心,不要让您的领域模型因为数据库设计而受到影响。应该始终是数据库跟随,而不是领域模型,您不进行某些更改,因为很难在数据库中迁移。