【发布时间】:2026-01-10 01:25:01
【问题描述】:
我被 Eric Evans 的书说服了,并且正在将 DDD 集成到我的框架中。所有基本元素(服务、存储库、限界上下文等)都已实现,现在我正在寻找有关如何正确集成这些元素的反馈。
我有一些业务逻辑必须在创建或修改实体时执行。这个例子是一个非常简单的例子。大多数业务逻辑将变得更加复杂。
这个业务逻辑可以分解为以下动作:
- 更新计算字段;
- 更新聚合根内的子记录。在创建聚合根时,这需要创建默认子记录。更新聚合根时,如果聚合根上的特定字段发生更改,则需要删除现有子记录并创建新记录;
- 将聚合根的开始和结束日期传播到聚合根内子记录的开始和结束日期。在某些情况下,这些必须保持同步;
- 将聚合根的字段传播到不同的聚合根。
我的第一次尝试是将所有这些都放在聚合根上,但我觉得这行不通。我在集成此逻辑时遇到以下问题:
- 所有这些操作必须作为一个整体完成,不应作为单独的操作提供。这导致测试非常困难 (TDD);
- 我不清楚这些操作是否可以移出到服务中。这样做的原因是它们在聚合根之外毫无意义,但它会使 TDD 更容易;
- 根据是创建新实体还是修改现有实体,某些逻辑会发生变化。我应该将这两个分支放在更新逻辑中,还是应该创建两个完全不同的路径来共享不区分基于创建/修改的业务代码。
对于上述问题的任何帮助以及其他一般反馈将不胜感激。
【问题讨论】:
-
你真的要向孩子们传播价值观吗?即你不能只对从父级读取值的子级使用 getX() 方法吗?例如Child.getX() {返回 parent.getX();}。甚至可能使您不必更换孩子。只是一个想法。
-
旧版应用程序。你要做什么:)。
-
wrt @Kdeveloper 对服务的评论。 DDD 确实在谈论服务。风险在于所有业务逻辑最终都在服务中,将对象仅作为数据容器(下面提到的“贫血数据模型@orangepips”)。因此,DDD 建议基本上是:首先,询问任何域行为属于哪个对象。如果它真的不属于单个对象,那么 - 并且只有这样 - 将它放入域服务中。
-
我还想引用 Evans DDD,关于服务的章节(第 104 页):“有一些重要的域操作无法在实体或值对象中找到自然归宿。其中一些本质上是活动或动作,而不是事物,但由于我们的建模范例是对象,所以无论如何我们都会尝试将它们拟合到对象中。现在,更常见的错误是放弃将行为拟合到适当的对象中,逐渐滑向程序化编程。”
-
非常同意以上所有。只有最后的评论是要警惕您对“服务层”一词的看法。将其可视化为“上方”的一层或提供对域实体/值的访问是有危险的。这反过来又会滋生一种误解,即其他层(例如应用层)只能调用服务,而不能直接调用域实体/值上的操作。这是不对的 - 并且可能导致贫血的域模型。最好将“域层”视为由具有同等地位的域实体、值和服务组成。
标签: oop design-patterns tdd domain-driven-design