【问题标题】:Which layer should Repositories go in?Repositories 应该进入哪一层?
【发布时间】:2010-08-17 03:27:18
【问题描述】:

存储库类应该进入哪一层?域还是基础架构?

【问题讨论】:

  • DDD 提倡在域层中不存在任何基础设施问题。基础设施层是存储库的理想场所。要使用存储库,从服务层引用它们的接口就足够了。

标签: domain-driven-design repository-pattern ddd-repositories


【解决方案1】:

存储库接口是域的一部分。接口的实际实现应该是基础设施的一部分。

【讨论】:

  • 说得好。接口是域的一部分,因为它定义了 DO 可访问的合同。它经常被忽视。
  • 定义分层架构的规则怎么样(见我的回答)?
  • 很好的问题。存储库接口在域层和基础设施层之间共享的数据定义模块中定义。它意味着一种放松的分层形式。正如在《软件架构模式》一书中所述,p。 39: »Layer J 提供的函数的参数、返回和错误类型应该是编程语言的内置类型、Layer J 中定义的类型,或者取自共享数据定义模块的类型。请注意,层之间共享的模块放松了严格分层的原则。«
  • 你说的这本书是“面向模式的软件架构”,第39页的内容可以看here as well,在第4步。但是你的评论误解了它所说的:“数据定义“在层之间共享”的模块”是域实体类型,不是存储库接口。在 DDD 中,域实体进入域层(参见 DDD 书)。即使我们将实体放入基础设施层,“面向模式”一书中也没有说“J”层中的组件可以依赖于更高层“J+1”。
  • 那是完全错误的。存储库的接口不应该是域层的一部分。阅读我的回答了解更多详情。
【解决方案2】:

存储库实现类以及单独的接口(如果存在)应该进入领域层

原因在于分层架构中要遵循的基本规则:下层不能依赖上层

如果我们接受这个规则(否则它不是分层架构),那么将存储库实现放入基础架构层会使其依赖于领域层,因此违反了分层的基本规则。

例如,当我们创建一个新的领域实体时,我们把它放在领域层;并且由于存储库(其接口和实现)必须不可避免地依赖于域实体,这意味着存储库也必须进入域层。否则,只要在域层中添加/删除/修改域实体,我们就会更改基础架构层。

其他问题,例如保持域层“干净”和独立于持久性细节,可以而且应该通过使用来自域层内部实现的适当基础设施服务来实现。例如,在 Java 中,我们可以使用 JPA 用很少的代码来实现存储库,并且不需要 SQL/JDBC 或数据库特定的代码(使用 JPA 实现存储库是否真的是一个好主意是另一个讨论;无论如何,JPA 实体将无论如何都要使用 JPA 注释)。

参考:Wikipedia, MSDN

【讨论】:

  • 让领域层依赖于基础设施层会使领域层变得脆弱且不可跨应用程序重用。通常,在构建域模型时,人们会希望独立于基础设施,这会反转依赖关系。基础架构必须依赖于领域模型,而不是相反。
  • @Shade 也许您正在考虑某种架构风格,而不是来自领域驱动设计 (DDD) 的架构风格。在 DDD 中,领域层包含应用程序的所有(或至少大部分)业务逻辑,以及整个数据模型(由一组实体和值对象类型表示)。不可能在另一个应用程序中重用它(除非它只是具有不同的 UI,实际上这从未发生过)。
  • 也许我有一些误解——我指的是来自 Clean Architecture (blog.cleancoder.com/uncle-bob/2012/08/13/…) 的概念,它与领域驱动设计兼容。在 Clean 中,域是最内层,没有任何依赖关系。它确实包含所有领域逻辑,但没有特定于应用程序的逻辑,也没有基础设施问题。为了更好地理解,你有一个例子来说明你的意思吗?
  • 我的桌子上现在有 Evans 的书 - 你能指出哪些部分特别使它与 Clean 不兼容吗?阅读第 70 页,最底部的一段,它说“将与域模型相关的所有代码集中在一个层中,并将其与 UI、应用程序和基础架构代码隔离开来。......将领域层与基础架构和 UI 层分开允许每一层的设计都更加简洁。”按照我的理解,这意味着领域层应该依赖于任何其他层,这也是Clean and co的前提。
  • @ziGi 在这种情况下,“依赖”表示编译时依赖。所以,是的,领域层中的组件将调用来自下面基础设施层的组件上的方法。这是 DDD 书中所描述的内容,也是实际项目中常用的内容(根据我的经验)。在 DDD 中,Repository 不是基础设施组件,而是 Domain 组件; DDD 为领域模型定义了五种这样的组件:实体、值对象、工厂、领域服务和存储库。
【解决方案3】:

存储库类的实现应该位于基础设施层。存储库接口应该在服务层中。

域层应该对存储库一无所知。 DDD 的战略模式表明领域层应该始终与概念模型同步。这意味着域层应该将众所周知的域进程转换为代码,反之亦然。领域流程是您的领域专家应该了解的。而且领域专家对存储库一无所知。

另一种思考方式。假设我们将存储库或存储库接口放入域层。 IE。现在我们在领域层代码中有了存储库的概念。此外,领域层应该与领域的概念模型同步。所以,让我们问问自己,概念模型中存储库的表示是什么。正确答案是概念模型中没有存储库。因此,存储库不能在域层中。

总而言之,我仍然遇到在领域层中有存储库的项目,并且项目的工程师仍然将其称为 DDD 实践。我认为这里的问题是人们并没有过多关注位于 DDD 核心的战略模式,而只是玩弄可以稍微简化编码工作的战术模式。

【讨论】:

  • 愿意出示任何证据来支持您的主张吗?例如,在 DDD 书中的什么地方?或其他作者/来源?还是只是您的个人意见?
  • @Rogério,让我们从一个简单的事情开始,这将使您更好地理解。领域层的目的是什么?请你回答一下好吗?
  • @Rogério,您所有问题的答案也在我的回答中。请花点时间仔细阅读,然后再跳到上面回答的问题。
  • 在 DDD 中,域层包含域模型的所有源代码,包括实体、值对象、工厂、域服务和存储库。 DDD 定义了一个四层架构,最顶层是 UI 层,然后是应用层,然后是领域层,最后是基础设施层。编译时依赖只允许从较高层到较低层。你根本没有回答我的问题,我要求参考,你没有。另外,我没有说 DL 可以有“基础设施问题”。请阅读我回答的最后一段,我在那里举一个具体的例子。
  • @Rogério,如果我的证明链不需要任何资源,我不需要它们。我的答案是我的证明链。否则,您可以将我的答案视为资源。因此,正如我所见,您对 DDD 的核心——战略模式知之甚少。鉴于此,我认为没有理由继续与您讨论。请在开始此类讨论之前学习 DDD。
【解决方案4】:

我想这取决于你将如何依赖他们。

问题是 - 您是否允许自己使用域内部的存储库?
如果是这样 - 那么你就不得不把它们放进去。

我自己喜欢将它们放在域之外。所以 - 某事物的典型生命周期如下所示 =>

UI => 控制器 => 从 repo 中检索聚合根 => 通过聚合根调用逻辑 => 如果创建了新的聚合根,则将其添加到 repo。

有时控制器调用应用程序服务,除了检索根目录和调用函数之外,它还会做一些额外的事情。但想法是一样的——域对持久性一无所知。


虽然(如我所见)将 repos 放入域(或至少是它们的抽象)中没有错,但它使您的域更加了解持久性。有时这可以解决问题,但通常 - 这肯定会使您的域更加复杂。

使用对你来说更自然的东西,随时准备改变你的方式。

【讨论】:

  • 我会说这取决于我们是否想要分层架构;如果我们这样做,那么别无选择:存储库进入领域层。
  • I guess that depends how You are going to rely on them. 这是一个错误的猜测。根据 DDD,领域层应该清楚任何基础设施问题,没有其他选择。阅读我的回答了解更多详情。
  • @manyanymore 的“答案”毫无意义。对于那些感兴趣的人,我会在我的 cmets 中解释原因。
猜你喜欢
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-04-28
  • 2013-08-03
相关资源
最近更新 更多