有一段时间我正在处理域驱动设计。不幸的是,我在聚合方面遇到了一些问题。
说,我喜欢模拟大学的结构。大学有一些部门(院系),每个部门都有一些课程。有一条规则,即每个部门都需要独特,因此每个部门都需要。例如,类的名称必须是唯一的。如果我理解正确,那么“大学”似乎是我的聚合根,“部门”和“类”是这个聚合中的实体。
还有另一个聚合根“教授”,因为它们是全球可访问的。他们将被分配到一个班级。我不确定它是否被允许,因为聚合根应该只指向另一个聚合根而不指向其内容。
如何处理? 感谢您的帮助, 提前谢谢!
答案 0 :(得分:3)
说,我喜欢模拟大学的结构。大学有一些部门(院系),每个部门都有一些课程。有一条规则,即每个部门都需要独特,因此每个部门都需要。例如,类的名称必须是唯一的。
真的?为什么?该规则的商业价值是什么?如果碰巧有两个同名的班级,那么企业(大学)的成本是多少。这是指所有时间都是同一个名字,还是只是在给定的学期内?
DDD的部分要点是解决方案的设计需要探索“无所不在的语言”以充分了解需求。
换句话说,您可能无法在设计中找到适合此要求的因素,因为您尚未发现所需的所有实体,使其按照业务专家的预期运作。
Udi Dahan指出唯一性规则可能根本不属于域名:
不是必须在域模型中实现不属于真正域逻辑的规则,因为他们不对域建模。
因此,如果您有这样的约束,但约束不是域本身的结果,那么约束可以在其他地方正确实现。
Greg Young还撰写了关于set validation的文章,专门解决了对最终一致性的担忧。
但广泛地说,是的 - 如果你真的拥有一组实体,并且一个域规则跨越集合中的多个元素,那么你需要一些聚合来保持集合所在边界的完整性。
实体不一定是你的想法。例如,如果您需要名称是唯一的,并且类实体的其余部分仅用于搭载,那么您可以通过创建名称注册表聚合来简化规则;教授为其班级保留名称,如果保留可用,则保留名称可以应用于班级实体。
如果您的核心业务确实在命名,需要考虑许多特殊的不变量,那么您可以围绕这个构建一个大型模型。但那并不是特别可能;也许你可以把一两个表打成一个关系数据库 - 这是设置验证问题的一个很好的解决方案 - 并继续使用项目中有价值的部分。
还有另一个聚合根“教授”,因为它们是全球可访问的。他们将被分配到一个班级。我不确定它是否被允许,因为聚合根应该只指向另一个聚合根而不指向其内容。
class.assign(professorId);
通常是这里的答案 - 您传递标识聚合根的代理键。您域中的每个实体都应该有一个。
这里有一些注意事项:我发现现实世界的实体(特别是人)并不是一个有用的起点,可以确定聚合的用途。主要是因为它们最终是表示在域模型之外强制执行不变量的数据。
另外,我发现从名词班,系,教授开始,往往把重点放在CRUD上,这通常不是一个非常有趣的问题。
相反,我建议考虑做一些有用的事情 - 一个有强制执行业务规则的用例,当业务模型说“不,业务不会让你现在就这样做”。
答案 1 :(得分:0)
问自己这些问题:
部门将引用其类作为包含Class聚合根id和类名的值对象列表并不是问题。对于处理班级的部门来说,这同样有效。
弗农的Effective Aggregate Design也可能会有所帮助。
答案 2 :(得分:0)
我对DDD也不是很有经验,但这里有一些我用过的技巧:
为什么将类定义为聚合而不是值对象?因为值对象通过其属性的值而不是ID来区分。我会说,即使有两个具有相同名称,相同学生,相同信息等的课程,企业仍然希望区分每一个。它与1美分硬币不同,你只关心价值(由颜色,大小,重量......给出),但你总是可以用另一个具有相同属性值的硬币替换它,即1分。同时将另一位教授分配给该类,该类保持不变,它不是一个值对象应该是不可变的。