1

我一直在阅读人们所说的关于 DDD 上下文中存储库位置(在哪一层)的内容,并发现我觉得不对劲的事情。例子:

确实,“就更“经典”的 DDD 而言,是的,域对象通常不允许在域之外的任何地方。

这里

任何机构都可以指出我的其他参考资料,说明类似的情况吗?或者至少解释为什么?

对我来说正确的是一些存储库属于域层。正如埃文斯所说,存储库必须主要用于返回聚合以避免:

...违反域对象和聚合的封装...

并遵循:

...存储库减轻了客户的巨大负担,它现在可以与一个简单的、意图揭示的界面对话,并根据模型询问它需要什么...

因此,如果聚合是域对象并且由一些存储库返回,导致我们拥有必须知道如何重建这些域对象的存储库,则此类存储库实现将与域层的其他部分有非常密切的关系,例如简单的聚合类定义或重建工厂。

这些想法让我想到了第二个问题,App Layer 是否习惯性地从Naked Object上下文之外的存储库中检索域对象?我觉得是的,并且当性能或其他特定原因证明它是合理的时才需要使用数据传输对象,但是如果我们以避免知识泄漏的方式设计域层接口(只需公开所需的域对象和域服务到应用层而不是内部层),我们将是安全的。有没有感觉到这种思路?

我在前面的段落中说过一些,因为我认为某些存储库可能与域层没有那么紧密的联系,我谈论的是存储库以访问某种值或可枚举的对象,或者一般来说,与域没有关联的对象。Evans 也谈到,他认为有些时候全局搜索是有感觉的,这种全局搜索不会对设计造成任何伤害。

存储库存在的另一个原因是避免:

暴露技术基础设施和数据库访问...

将应用程序和域设计与持久性技术、多个数据库策略甚至多个数据源解耦。

存储库模式的其他目标让我一开始认为存储库不能在域层上,这与我已经说过的相矛盾。

最后,我认为如果我们根据其层位置对它们进行分类,则存在两种类型的存储库:

1-属于基础设施层的一个接口返回非领域层对象,避免最低层依赖于最高层。应用层将主要使用这种存储库来检索某种 VALUES/ENUMERABLE 对象。

2- 其他类型的存储库返回域对象并驻留在域层中。这种类型的存储库依赖于基础设施层提供的接口,用于基本上将应用程序和域设计与持久性技术分离,同时允许应用程序层在意图揭示接口中与域对话,并根据模型询问它需要什么。基础设施提供的这类接口可以用简单的原始数据合约来表达,并且看起来像是第二种形式的存储库,领域层通过该存储库向基础设施层询问形成领域对象和回复所需的数据来自应用层的请求。在我看来,实际上我可以以重复的代码结束在域对象非常简单且形式类似于它们在数据库中的存储方式的情况下。对于这些问题以及如何组织代码以在 DDD 的上下文中解决这些问题,我将不胜感激。

我将感谢这些想法的批评者,主要是那些突出其软点的人;)

这是我正在谈论的图表

在此处输入图像描述

编辑:

我对此了解得越多,我就越认为这种区别非常重要,并且可以让社区有所了解。例如,这里描述的是基础设施存储库(我写的类型 1),而这里描述的是域存储库(我写的类型 2)。

更重要的是,我认为像这样的战斗的一部分是因为我没有在这里做出的区分而被提升的。

4

2 回答 2

1

避免最低层依赖于最高层

  • 相反,应该避免;)高级模块不应该依赖于低级细节

  • 如果较低级别的详细信息位于底部,则域层在您的架构上放错了位置。它应该出现在顶部。

    可以这样想:领域层包含您的核心业务概念和行为。您是否打算在保持相同的应用程序层的同时完全更换该域?不太可能工作/没有任何意义。

    相反,您可以保留域模块并更改应用程序层(想想移动应用程序、公开您的域的 Web 服务等)。对于基础架构也是如此 - 您可以更改数据库,您可以将邮件发件人更改为另一个。应用程序依赖于域并为其量身定制。基础设施也依赖于域。不是反过来。

这给出了典型的以下设计:

  • 领域层中的存储库抽象(接口)。这些暴露了操纵域对象(聚合根)的合约。

  • 基础设施层中的存储库实现。基础设施依赖于领域,因此从上述抽象派生具体存储库没有问题。

  • (可选)基础设施层中的存储库基类。这些是为了排除所有存储库共有的元素,通常与底层持久性技术(数据库连接、ORM 更改跟踪器等)有关。

  • 应用层类只知道来自域层的存储库抽象,但在运行时注入了在基础设施中定义的具体实现。

这些想法让我想到了第二个问题,App Layer 是否习惯性地从 Naked Object 上下文之外的存储库中检索域对象?我觉得是的,并且当性能或其他特定原因证明它是合理的时才需要使用数据传输对象,但是如果我们以避免知识泄漏的方式设计域层接口(只需公开所需的域对象和域服务到应用层而不是内部层),我们将是安全的。有没有感觉到这种思路?

这是正确的(更不用说“内部”域对象和服务几乎没有理由存在)。

于 2013-10-21T12:31:19.440 回答
0

我不是 DDD 专家,我仍在学习它,但我尝试回答您的问题。这个答案可能不容易理解,因为我使用了不同的术语。我有 4 层:表示层、应用程序层、域层和基础设施层。这与您的 3 层架构非常不同。可能你的应用层是我的表示层,你的领域层是我的应用+领域层,但我不确定。

任何机构都可以指出我的其他参考资料,说明类似的情况吗?或者至少解释为什么?

我不认为那是真的。AFAIK。应用服务在应用层。在某些图中,该层是表示的一部分,而在其他图中,它位于表示和域之间。这些服务处理来自演示文稿的命令和查询。这很好,因为您始终可以编写不同的演示文稿,例如移动客户端,同时您可以重用相同的应用程序服务。维护也更容易,因为您不必在演示文稿中找到任何与域对象相关的代码。这种代码只会出现在应用程序层和领域层中。另一个原因是您可以在这里轻松地将域访问代码放入事务中。

这些想法让我想到了第二个问题,App Layer 是否习惯于从 Naked Object 上下文之外的存储库中检索域对象?

很难回答这个问题,因为您错过了这里的表示层。是的,域对象可以在应用层访问,但不能在表示层访问。应用层和表示层相互发送 DTO,而不是域对象。所以 UI 永远不会使用域对象,而只会使用 DTO。因此,您的域对象将保留在它们的事务中,并且 UI 可以使用 DTO 来显示内容。DTO 可以具有与域对象不同的属性,并且也可能具有不同的验证。

关于存储库。它们的接口在域中定义,并在基础设施中实现。这很重要,因为这样基础设施将依赖于域,因为域定义了它必须实现的接口。域服务也可能发生同样的情况。因此,如果您的域服务具有基础架构依赖项,那么您可以在域中定义一个接口,并在基础架构中实现它。我不确定这些图中箭头的含义。为了使您的应用程序正常工作,您需要将这些实现注入应用程序和域层类的实例中,但这些类仅依赖于域层定义的接口。换句话说,这是控制反转。所以领域层的类不能依赖领域层之外的任何类。例如,您可以在基础架构中拥有 ORM 存储库,所以是的,可以有与域相关的存储库和与基础架构相关的存储库,但您不应该混淆它们。

我想我只是写了和 guillaume31 一样的东西。:-) 可能您链接的图:http ://www.ajlopez.com/images/articles/dddlayered.png有一些错误。域中的类不能依赖于基础设施中的类。这里最重要的规则是,一切都取决于域的类和接口,而不是相反……我读过 Vernon 的书,我可能读过 Evan 的书,但我不确定。我在这个主题上阅读太多,并且没有比其他人那么多的实践经验。我目前正在一个相对较小的项目上练习 DDD,但我真的很喜欢它。

于 2017-02-23T13:01:19.550 回答