- 当应用程序使用存储库(这是一个基础设施服务)时,存储库接口被定义在域层中,而它的实现被定义在基础设施层中,因为这样域模型没有外向依赖关系。
a) 如果我们 100% 确定特定(非存储库)基础设施服务 InfServ永远不会被域层中的任何代码调用,那么我假设InfServ 的接口不需要在域层中定义?
- 假设InfServ不会被 Domain 层中的代码调用(因此我们不需要在Domain 层中定义它的接口):
a)如果InfServ将被Application 层的 Services调用,我假设Application 层应该对Infrastructure 层有隐式依赖,而不是相反?换句话说,InfServ 的接口和它的实现都应该在基础设施层中定义?
b)应用层依赖于基础设施层而不是其他方式更好的原因是基础设施层可以被许多应用程序重用,而应用程序层在大多数情况下仅特定于单个应用程序并且通常不能被其他应用程序重用?
c) 如果我们 100% 确定Domain 层中的任何代码都不会使用Repository,那么我们就不需要在Domain 层中定义它的接口了吗?
更新:
1)
是的,但是,域层的定义可以包括作为域外立面的应用程序服务。应用程序服务通常引用存储库和其他基础设施服务。它协调域对象和所述服务以实现用例。
一种)
...充当域的立面
难道我们不能争辩说“常规”(我在我的问题中提到的那些)应用程序服务也充当域的外观吗?
b)
应用程序服务通常引用存储库和其他基础设施服务。
从您的回复看来,您似乎在暗示(尽管您可能不是)“常规”应用程序服务通常不引用基础设施服务,实际上它们确实如此(据我所知)?!
2)
一种)
如上所述,我通常将应用程序服务合并到域层中。
“常规”应用层也是 BLL 层的一部分,所以我们不能说它与域层合并(它实际上位于域层之上)吗?!
b)
我倾向于坚持六边形的建筑风格...
看起来六边形架构没有明确的应用层概念(即应用服务)?
C)
在域层声明存储库接口的部分好处是它指定了域的数据访问要求。
所以即使我们的域代码不会使用它,我们也应该在域层中包含Repository 接口?
第二次更新:
2a)
如果您所说的“常规”应用程序服务与域交互,我认为将其作为域“层”的一部分是可以接受的。但是,域不应直接依赖于周围的应用程序服务,因此如果需要,可以将它们拆分为单独的模块。
我不确定您是否暗示应用层的设计(在传统的分层架构中)与您使用例如洋葱架构将应用层与域层合并时有什么不同?
我会说至少就模块而言,两者不应该不同,因为在这两种情况下我们都可以分离应用程序和域层模块?(尽管我必须承认我跳过了伴侣模块(Evan 的书),因为我认为在学习 DDD 时我不需要这些知识:O)
2b)
是的,因为它可以与分层架构进行对比。严格的分层架构不符合在领域层声明存储库接口并在基础设施层实现的想法。这是因为,一方面,您在一个方向上存在依赖关系,但在部署方面,依赖关系在另一个方向上。Hexagonal 通过将域置于中心来解决这些问题。看看洋葱结构——它本质上是六边形的,但可能更容易掌握。
我还不知道 MVC 模式或 Asp.Net MVC,但无论如何,从阅读本系列的前三部分(这让我感到困惑到我停止阅读它),它似乎:
a)来自洋葱文章:
每一层都耦合到它下面的层,并且每一层通常耦合到各种基础设施问题。
作者暗示在传统的分层架构 TLA 中,域层与基础设施层耦合,这当然不是真的,因为我们通常在域层内定义基础设施接口(例如存储库接口)?!
b) 如果在使用 TLA 时我们决定在应用层定义基础设施接口,那么应用层也不与基础设施层耦合?!
c)由于基础设施接口是在应用程序核心中定义的,因此洋葱架构不是与应用程序核心(包括应用程序层)耦合的*基础设施层*吗?
d)如果c)是,将应用程序层耦合到基础设施层不是更好吗(出于我在原始问题中给出的原因(这里我假设域层不会调用基础设施服务))?
4)
来自洋葱文章:
围绕领域模型的第一层通常是我们可以找到提供对象保存和检索行为的接口,称为存储库接口。
来自洋葱文章:
控制器仅依赖于在应用程序核心中定义的接口。请记住,所有依赖项都朝向中心。
看来作者是在暗示,由于依赖关系只是内部的,而且基础设施接口是围绕领域模型定义的,领域模型中的代码不应该引用这些接口。换句话说,我们不应该将存储库引用作为参数传递给域实体的方法(正如您自己所说的那样):
class Foo
{
...
public int DoSomething(IRepository repo)
{
...
var info = repo.Get...;
...
}
}
出于上述原因,我必须承认,我看不到使用Onion 架构的好处,甚至看不到它与 TLA 有何不同(假设所有基础设施接口都在域层中定义)--> 换句话说,我们不能描述 TLA使用洋葱架构图?!
最后更新:
2)
b)
是的。在 TLA 中,域层将根据基础设施层声明的类直接与基础设施通信,而不是相反。
只是为了确定——您是说使用 TLA,基础设施接口将在基础设施层中定义(我知道使用 Hexagonal/Onion 架构,它们是在应用程序核心中定义的)?
d)
耦合是双向的。应用程序核心依赖于基础设施中的实现,而基础设施依赖于应用程序核心中声明的接口。
我的观点是,由于 Onion 架构在应用层中声明了InfServ接口(这里假设InfServ从未被域层调用,因此我们决定不在域层中定义InfServ接口——参见原始1a问题),它表示应用层控制InfServ接口。但我认为如果基础设施层控制InfServ接口会更好,因为原始2b中所述的原因问题?!
4)
看来作者是在暗示,由于依赖关系只是内部的,而且基础设施接口是围绕领域模型定义的,领域模型中的代码不应该引用这些接口。
在我看来,您的代码示例适合编码。
所以我说洋葱架构不允许“域模型”引用基础设施接口是正确的,因为它们是在 InDe 层中定义的( InDe当然也驻留在应用程序核心中)围绕 DM强文本并从DM引用它们意味着依赖关系从DM上升到InDe?
DDD 通常以六角形/洋葱形架构风格呈现,这就是为什么可能会有一些混乱。我认为您可能一直在做的事情已经是六角形的,这就是为什么它看起来是同一件事的原因。
是的,我也有这种印象。虽然我确实计划在阅读完 Evan 的书后更深入地研究 Hexagonal 架构(特别是因为新的 DDD 书将基于它的一些示例)。
第四次更新:
2)
d)
如果基础设施拥有接口和实现,那么域或应用层将负责为自己实现持久性。
我假设应用程序或域层需要自己实现它,因为引用基础设施层中定义的接口将洋葱的内层规则不依赖于外层(基础设施层是外层)?
4)
领域模型可以引用基础设施接口,例如存储库,因为它们是一起声明的。如果应用层从域中分离出来,就像在洋葱图中那样,那么域层可以避免引用接口,因为它们可以在应用层中定义。
但是根据那篇文章,基础设施接口是在围绕Domain Layer的层中声明的,这意味着它比Domain Layer更接近应用程序核心的外边缘- 正如文章指出的那样,内层不应该依赖于外层>!
谢谢你