【问题标题】:DDD: Choosing aggregate rootDDD:选择聚合根
【发布时间】:2017-05-05 14:48:27
【问题描述】:

就我而言,我有两个主要概念:用户(系统的主要公民)和组。 组有两个子集合:等级和角色。没有组,等级和角色就没有意义。 当用户被分配到组时,我们还必须选择 1 个角色和 1 个等级并将它们分配给用户和组之间的这种关系。

Diagram

问题:

我这里有多少聚合根?从用户端看,它显然是一个用户(系统的主要概念),但它与组的关系呢? AFAIK 被 DDD 规则禁止引用聚合根之外的实体。

【问题讨论】:

    标签: domain-driven-design aggregate


    【解决方案1】:

    DDD 规则禁止引用聚合根之外的实体。

    好吧,我不会说它是“DDD 规则禁止的”... 有时您别无选择。我必须考虑与根聚合相关的“实体集合”的大小。有时您可以在同一聚合中维护关联并使用某种“延迟加载”来避免资源消耗。 Vernon 的 iDDD 书 [1] 围绕这个特定案例提供了一些建议和用例。看看他的博文[2]

    [1]https://www.amazon.com.br/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577 [2]https://vaughnvernon.co/?p=838

    【讨论】:

    • 或者可以使用最终一致性
    【解决方案2】:

    您至少有以下选项,具体取决于您对一致性的业务要求:

    1. 您有 5 个聚合根:User、Group、Rank、Role 和 UserAssignment。最后一个必须保护不变量“我们还必须选择 1 Role 和 1 Rank”。对于生命周期管理,您使用 AR 之间的最终一致性。例如,当您删除组时,您还必须删除孤立的 Ranks、Roles 和 UserAssignments。

    2. 您有用户(以 UserAssignment 作为嵌套实体)和组(以角色和等级作为嵌套实体)。您在 AR 内部具有很强的一致性(当您删除用户时,它的所有分配也会被删除)以及用户和组之间的最终一致性。

    你应该使用什么?只有你可以决定。例如,如果您选择第一个选项并删除用户,那么在删除其分配之前可能会延迟几秒/分钟/小时。

    应该使用强一致性来保护真正的业务不变量,因为它并不便宜。

    附:如果您需要从另一个 AR 中保存对嵌套实体的引用,那么您应该重新考虑您的聚合根边界,因为您的设计很可能是错误的。

    【讨论】:

    • 基本上没有父组,角色和等级都没有意义。就像:“你好,我是国王[角色]。” “什么[组]的国王?”。 “NullPointerException”。应用程序本身非常以用户为中心,一切都围绕用户的概念发展。在您的第二个选项中,碰巧我们有 2 个聚合 - 用户和组,对吗?但是用户分配(用户实体中的嵌套实体)引用了组聚合中的嵌套实体。是你的意思还是我没听懂?
    • 然后结合使用选项 1 和 2。我还试图让您了解在设计聚合时如何思考:一致性边界。没有绝对的答案。
    • 我们可以尽可能多地讨论您需要了解的内容,但没有人能准确告诉您该怎么做
    • 我当前的解决方案:实现 5 个聚合根:User、Group、Rank、Role 和 UserAssignment。角色和等级与其父组有关系,因为用户通常希望按照特定顺序(foobar[group] 的国王[role])遵循这种关系,而且该应用程序是 READ-heavy。接下来,我们只创建一个 GroupService 并将所有不变量推送到那里(例如:组中只能有 1 个国王 - createRoleForGroup(group, role)->loadKingRoleForGroup(groupId)->found nothing->save(role))。跨度>
    • 这种方法还允许我为我们的角色制定自定义规范(例如获取所有国王),从而优化查询。我将写入(它们通过组,从而保护不变量)和读取(只需要信息)分开。如果我想删除一个组 - 我首先检查活动的 UserAssignments,如果它们存在 - 停止执行(用户是事件源,我们必须先取消分配用户)。如果不是 - 删除它的子聚合和它自己。这种方法有效吗?
    【解决方案3】:

    我将更改一些单词,我们将看看它是否有帮助(假设):

    我有一个Order 和一个Product。当我将Product 添加到Order 时,我必须选择StoreColour

    你会如何建模?

    Colour 很可能是一个值对象,但Store 不是。我会选择一个OrderItem 值对象,它包含一个Colour 值对象和一个StoreId 值来捕获关系。 Order 将包含 OrderItem 条目的列表。

    删除Colour 条目很好,因为我们已将该位非规范化为OrderItem。我们可以让另一个值对象代表Store,但通常我们不会删除存储或进行一些处理来处理删除,或者更典型的是,使用引用完整性约束来防止删除使用过的@ 987654337@.

    如果您考虑删除 Order,则只会删除 OrderItem 关联。

    在您的情况下,UserGroup 可能是聚合根,我会添加一个 UserGroup(或 UserAssignment,因为康斯坦丁使用)。 UserGroup 包含关联和相关位。不过,您必须确定真正的域结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 2012-02-19
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多