【问题标题】:DDD: University as an aggregate rootDDD:大学作为聚合根
【发布时间】:2016-06-28 16:39:11
【问题描述】:

有一段时间我正在处理领域驱动设计。不幸的是,我在聚合方面遇到了一些问题。

比如说,我喜欢为一所大学的结构建模。大学有一些系(系),每个系都有一些课程。有一条规则,每个部门都必须是独一无二的,所以每个班级都必须是独一无二的。例如,类的名称需要是唯一的。如果我理解正确,那么“大学”似乎是我的聚合根,“部门”和“班级”是这个聚合中的实体。

还有另一个聚合根“Professor”,因为它们是全局可访问的。他们将被分配到一个班级。我不确定它是否被允许,因为聚合根应该只指向另一个聚合根而不是它的内容。

如何处理? 感谢你的帮助, 提前致谢!

【问题讨论】:

  • 如果您的域停止创建大学和课程并将教授分配给课程,我不会为此使用 DDD 战术模式。它基本上是 CRUD。只能根据更复杂的用例和事务分析来设计聚合(我猜最终用户不会急于每天以高度并发的方式添加更多大学或分配教授)
  • “聚合只能根据更复杂的用例来设计”这是一种奇怪的说法。 AR 可能不是最适合解决简单问题的,但它们肯定也可以用来解决这些问题。

标签: domain-driven-design


【解决方案1】:

比如说,我喜欢为大学的结构建模。大学有一些系(系),每个系都有一些课程。有一条规则是,每个部门都必须是独一无二的,因此其中的每个班级都必须是独一无二的。例如,类的名称需要是唯一的。

真的吗?为什么?该规则的商业价值是什么?如果碰巧有两个同名的班级,企业(大学)的成本是多少。这是否意味着所有时间都使用相同的名字,或者只是在给定的学期内?

DDD 的部分观点是解决方案的设计需要探索“无处不在的语言”以全面了解需求。

换句话说,您可能无法在设计中找到适合此要求的合适方案,因为您尚未找到使其按业务专家期望的方式工作所需的所有实体。

Udi Dahan指出唯一性规则可能根本不属于域:

不属于真正领域逻辑的规则不必在领域模型中实现,他建议,因为它们不为领域建模。

因此,如果您有这样的约束,但该约束不是域本身的结果,那么该约束可以在其他地方正确实现。

Greg Young 还写过关于 set validation 的文章,专门解决了对最终一致性的担忧。

但从广义上讲,是的——如果你真的有一个实体集合,以及一个跨越集合中多个元素的域规则,那么你需要一些聚合来保持集合所在边界的完整性。

实体不一定如您所想。例如,如果您需要名称是唯一的,并且类实体的其余部分只是顺其自然,那么您可以通过创建名称注册表聚合来简化规则;教授为他们的班级保留名称,如果保留可用,则保留的名称可以应用于班级实体。

如果您的核心业务真的是命名事物,需要考虑许多特殊的不变量,您可能会围绕此构建一个大模型。但这并不是特别可能。也许您可以将一两个表添加到关系数据库中——这是解决集合验证问题的好方法——然后继续进行项目中有价值的部分。

还有另一个聚合根“教授”,因为它们是全局可访问的。他们将被分配到一个班级。我不确定它是否被允许,因为聚合根应该只指向另一个聚合根而不是它的内容。

class.assign(professorId);

是这里通常的答案——您传递标识聚合根的代理键。您域中的每个实体都应该有一个。

这里有几点注意事项:我发现现实世界的实体(尤其是人)并不是确定聚合用途的有用起点。主要是因为它们最终成为数据的表示,主要是在域模型之外强制执行不变量的数据。

另外,我发现从名词开始 - class、department、professor - 倾向于将重点放在 CRUD 上,这通常不是一个非常有趣的问题。

相反,我建议考虑做一些有用的事情——一个需要强制执行业务规则的用例,当业务模型说“不,业务现在不允许你这样做”时。

【讨论】:

    【解决方案2】:

    我在 DDD 方面也不是很有经验,但这里有一些我常用的技巧:

    • 是否可以有一个没有分配部门的班级?如果是这种情况,则 Department 是聚合根,Class 是另一个引用根的聚合,即 Department。您甚至可以在您的部门中定义一个工厂方法“addClass()”,其中包含需要创建类的信息,因此不应允许任何人在没有部门的情况下创建类。

    为什么将类定义为聚合而不是值对象?因为值对象是通过其属性的值而不是 ID 来区分的。我想说,即使有两个具有相同名称、相同学生、相同信息等的班级,企业仍然希望区分每个班级。这与 1 美分硬币不同,您只关心价值(由颜色、大小、重量等给出),但您始终可以将其替换为具有相同属性值的另一枚硬币,即 1分。还为班级分配了另一个教授,班级保持不变,它不像值对象应该是不可变的。

    • 我想教授必须是唯一标识的,他可能被分配到不同的班级甚至系。所以对我来说,这是另一个与部门分离的聚合根。

    【讨论】:

      【解决方案3】:

      问自己这些问题:

      • 您的系统中有多少所大学?如果这只是一个,则它不是您的聚合根。
      • 如果您的系统中有多个大学,是否会有人跨大学工作?大学可能是您的系统租户吗?
      • 如果某个部门解散,班级会怎样?它会立即消失吗?我对此表示怀疑。
      • 大学与系的关系同上

      Department 将对其类的引用保存为包含类聚合根 id 和类名的值对象列表,这不是问题。这同样适用于处理其课程的部门。

      弗农的Effective Aggregate Design 也可能有帮助。

      【讨论】:

      • 感谢您的回答。我没见过这种方式。所以部门和班级是聚合根。我已经多次阅读 Vernon 的文档,但我对 DDD 还没有太多经验。当某些概念受到 DDD 之前的经验(贫血领域模型,关于持久性的技术问题)的影响时,它们很难理解。 :-)
      • 当然,我会将 Department 和 Class 作为单独的聚合,因为它们来自不同的来源并服务于不同的目的。除了聚合根实体之外,您并不经常需要聚合中的其他实体。
      猜你喜欢
      • 1970-01-01
      • 2016-03-21
      • 1970-01-01
      • 2012-02-19
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多