与Application和Infrastructure层之间的依赖关系有些混淆

时间:2013-01-29 18:23:39

标签: domain-driven-design

1)当应用程序使用存储库基础结构服务)时,存储库接口中定义域层,而其实现是在基础架构层中定义的,因为域模型没有传出依赖关系。

a)如果我们100%确定任何代码都不会调用特定的(非存储库)基础结构服务 InfServ 域层中,我假设 InfServ 接口不需要定义在域层中?

2)假设 InfServ 不会被域层内的代码调用(因此我们不需要在域层中定义其接口>):

a)如果应用程序层的服务将调用 InfServ ,我认为应用程序层应该具有隐式依赖性基础架构层而不是相反?换句话说, InfServ 接口其实现都应该在中定义基础设施层

b)为什么应用层更好地依赖基础设施层而不是其他方式是因为基础设施层 em>可以被许多应用程序重用,而应用程序层在大多数情况下仅针对单个应用程序,并且通常不能被其他应用程序重用?

c)如果我们100%确定域层中的代码不会使用存储库,那么我们就不需要在其中定义其接口域层

更新

1)

  

是的,但是域层的定义可以包括应用程序   充当域名外观的服务。应用程序   服务通常引用存储库和其他基础结构   服务。它协调域对象和要实现的服务   用例。

A)

  

......作为域名的立面

我们不能认为"常规" (我在我的问题中提到的那些)应用程序服务也充当域的外观?

b)中

  

应用程序服务通常引用存储库和其他服务器   基础设施服务。

从您的回复中,似乎您建议(尽管您可能不会)#34;常规" 应用程序服务通常不会引用基础结构服务,实际上它们是这样做的(据我所知)?!

2)

A)

  

我通常将应用程序服务(如上所述)合并到   域层。

"定期" 应用层也是BLL层的一部分,所以我们不能说它与域层合并(它实际上位于域之上)图层)?!

b)中

  

我倾向于坚持六角形建筑风格......

看起来六角形架构没有应用层(即应用服务)的明确概念?

c)

  

在域中声明存储库接口的部分好处   layer是指定域的数据访问要求。

所以我们应该在域层中包含 Repository接口,即使我们的域代码不能使用它?

第二次更新:

2a)

  

如果您称之为"常规"应用程序服务与之交互   域名,我认为将其作为域名的一部分是可以接受的   "层&#34 ;.但是,域名不应该直接依赖于   周围的应用程序服务,因此可以将它们拆分   如果需要,可以分成不同的模块。

  • 我不确定您是否暗示应用层(在传统的分层架构中)的设计与合并使用域层的应用层,例如,洋葱架构

  • 我至少就模块而言,两者不应该不同,因为在这两种情况下我们都可以分开 Application 域层模块? (虽然我必须承认我跳过模块上的章节(Evan的书),因为我并不认为我很早就需要这些知识来学习DDD:O)

2b)

  

是的,因为它可以与分层架构形成对比。一个严格的   分层体系结构并不具有声明的概念   域层中的存储库接口和实现   基础设施层。这是因为一方面你有一个   依赖于一个方向,但在部署方面依赖性   在另一个。 Hexagonal通过放置这些问题来解决这些问题   域名在中心。看看洋葱建筑 - 它是   基本上是六角形但可能更容易掌握。

我还不知道MVC模式或Asp.Net MVC,但无论如何,从阅读系列的前三部分(让我困惑到我停止阅读它的那一点),它出现了:

a)来自Onion article

  

每层都耦合到它下面的层,每层都经常   加上各种基础设施问题。

作者暗示在传统的分层架构TLA中,域层耦合到基础架构层,这当然不是真的,因为我们通常定义 域层中的基础设施接口(例如存储库接口)?!

b)如果在使用TLA时我们决定在应用层中定义基础设施接口,那么应用层也不是耦合到基础设施层?!

c)不是洋葱架构和*基础架构层*耦合到应用核心(包括应用层),因为基础架构接口< / em>在 Application Core 中定义?

d)如果 c)为“是”,那么将应用层基础架构层结合起来是不是更好(原因我在我的原始问题中给出了(这里我假设Domain层赢得了“基础设施服务”)?

4)

来自Onion article

  

领域模型周围的第一层通常是我们想要的   查找提供对象保存和检索行为的接口,   称为存储库接口。

来自Onion article

  

控制器仅依赖于接口,接口在接口中定义   应用核心。请记住,所有依赖都是针对   中心。

似乎作者暗示,由于依赖关系仅是内部的,并且由于基础结构接口是围绕域模型定义的,因此域模型中的代码应该依赖于此接口。换句话说,我们不应该将Repository引用作为参数传递给Domain实体的方法(正如您自己所说的那样):

class Foo
{
           ...
       public int DoSomething(IRepository repo)
       {
              ...
            var info = repo.Get...;
              ...
       }
}

由于上述原因,我必须承认我没有看到使用洋葱架构的好处,甚至看不出它与TLA的区别(假设所有基础架构接口都已定义在域层中 - &gt;换句话说,我们不能使用洋葱架构图来描绘TLA吗?!

最终更新:

2)

b)

  

是。在TLA中,域层将直接与之通信   基础架构层声明的类的基础结构   不是相反。

只是为了确定 - 您已经说过,使用TLA,基础架构接口将在基础架构层中定义(我知道它们采用六边形/洋葱架构在应用程序核心中定义?

d)

  

耦合是双向的。应用程序核心取决于   基础设施和基础设施的实施取决于   在应用程序核心中声明的接口。

我的观点是,自Onion架构以来,应用层中声明 InfServ 接口(此处为假设 InfServ 永远不会被域层调用,因此我们决定不定义 InfServ 域层中的接口 - 请参阅原始 1a 问题),这意味着应用层控制 InfServ 界面。但我认为,如果基础设施层控制 InfServ 接口,那会更好在原来的 2b 问题中说明了什么?!

4)

  
    

似乎作者暗示,因为依赖只是向内     由于Infrastructure接口是围绕Domain Model定义的,     域模型中的代码不应该引用这些接口。

  
     

在我看来,您的代码示例是适当的代码。

所以我说Onion Architecture没有&#34;允许&#34; 域模型引用基础结构接口,因为它们是在 InDe 中定义的( InDe 当然也位于<围绕DM 强文本**并从** DM 引用它们的em>应用程序核心将意味着依赖性从 DM 上升到 InDe < /强>

  

DDD通常呈六角形/洋葱式建筑风格   这就是为什么可能会有一些混乱。我想你可能是什么   一直在做的已经是六角形的,这就是为什么它看起来像是   同样的事情。

是的,我也有这样的印象。虽然我计划在阅读Evan的书之后,更深入地了解六角形结构(特别是因为新的DDD书将基于它的一些例子)。

第四次更新:

2)

d)

  

如果基础设施拥有接口并实现域名   或应用程序层将负责实现持久性   为了它自己。

我认为应用程序层需要为自己实现它,因为在基础架构层中定义的引用接口将是Onion&#39; s内层规则不依赖于外层( Infrastructure层是外层)?

4)

  

域模型可以引用基础结构接口,例如a   存储库,因为它们是一起声明的。如果是应用层   从域中分割,如在洋葱图中,然后是域图层   可以避免引用接口,因为它们可以在中定义   应用层。

但根据该文章,基础设施接口域层周围的层中声明,这意味着它更接近应用程序核心<的外边缘/ em>而不是域层 - 正如文章指出的那样,内层不应该依赖外层&gt;!

谢谢

2 个答案:

答案 0 :(得分:2)

1a)是的,但是域层的定义可以包括在域上充当facade的应用服务。应用程序服务通常引用存储库和其他基础结构服务。它协调域对象和所述服务以实现用例。

2a,b)

我通常将应用程序服务(如上所述)合并到域层中。我倾向于遵循Hexagonal architecture样式,也称为端口和适配器。域位于中心,由应用程序服务封装,所有外部连接(包括存储库,UI和服务)都充当端口。

2c)在域层中声明存储库接口的部分好处是它指定了域的数据访问要求。

<强>已更新

1a)我并不打算将我提到的应用服务区别于&#34;常规&#34;应用服务。如果它是域上的外观,则适用规则。

1b)可能仍有一些服务称为应用程序服务,但与域名没有直接关系,我想排除这些服务。

2a)如果你称之为&#34;常规&#34;应用服务与域进行交互,我认为将其作为域&#34;层&#34;的一部分是可以接受的。但是,域不应直接依赖于周围的应用程序服务,因此可以根据需要将它们拆分为单独的模块。

2b)是的,因为它可以与分层架构形成对比。严格的分层体系结构并不适用于在域层中声明存储库接口和在基础结构层中实现的想法。这是因为一方面您在一个方向上具有依赖性,但在部署方面,依赖性在另一方面。六角形通过将域置于中心来解决这些问题。看看onion architecture - 它基本上是六角形的,但可能更容易掌握。

2c)是的,但通常应用程序服务会引用存储库接口。

更新2

2a)它们可以以不同方式实施,但一般责任是相同的。主要区别在于依赖图。虽然您可以使用任一架构将应用程序服务分离到自己的模块中,但洋葱/六边形体系结构强调使用接口来声明对基础结构的依赖性。

2ba)是的,这实际上是洋葱建筑的特征。

b)是的。在TLA中,域层将根据基础架构层声明的类直接与基础架构通信,而不是相反。

c)是的,基础设施实现了域层声明的接口。

d)耦合是双向的。应用程序核心依赖于基础架构和基础架构中的实现,这取决于应用程序核心中声明的接口。

4)在我看来,您的代码示例是适当的代码。在某些情况下,实体需要访问存储库才能执行某些操作。但是,为了改善此代码的耦合特性,最好定义一个声明实体所需功能的特定接口,或者更好地使用lambdas。然后,存储库可以实现该接口,并且应用程序服务将在调用给定行为时将存储库传递给实体。这样,实体不依赖于通用存储库接口,而是依赖于非常具体的角色。

DDD通常以六角形/洋葱式建筑风格呈现,这就是为什么可能存在一些混淆。我认为你可能做过的事情已经是六角形了,这就是为什么它看起来是同样的事情。

更新3

2b)在TLA中,没有接口,或者不是同一种接口。域将直接与基础架构通信,例如持久性框架,因此它将负责持久性。

2d)如果基础设施拥有接口和实现,那么域或应用层将负责为它自己实现持久性。在六边形/洋葱中,持久性的实现是基础设施的一部分 - 它适应&#34;数据库的抽象域。

4)域模型可以引用基础结构接口,例如存储库,因为它们是一起声明的。如果应用层是从域中分割出来的,就像在洋葱图中那样,那么域层可以避免引用接口,因为它们可以在应用层中定义。

更新4

2d)该声明不适用于具有以下层次结构的分层体系结构:UI - &gt;业务逻辑 - &gt;数据访问。业务逻辑层依赖于数据访问层,并且必须基于数据访问框架的对象模型来实现其数据访问。数据访问框架本身对业务层一无所知。

4)本文仅指定了一种可能的架构。有可接受的变化。

答案 1 :(得分:1)

我将存储库接口放在Application层而不是Domain中的唯一好处是,如果您想在另一个应用程序中重用域DLL,您将完全重新定义查询域实体集合的方式 - 换句话说,需要完全不同的存储库。

然而,这种方法存在两个主要障碍:

  • 域层服务。它们代表处于许多实体的十字路口的流程,因此需要多个引用来完成它们的工作。通过询问存储库来获取这些引用是一种常见且方便的事情。

    您可以在RoutingService here中找到相关示例。

  • 此外,还有一些特殊情况,某些实体可能需要存储库的帮助才能找到特定的其他实体。例如,如果您有一个聚合根的层次结构,它们之间有父/子关系,则一个特定实例可以说“我需要满足这些条件的所有祖先/后代的列表”。存储库似乎最适合这种查询。