通过聚合根(DDD)创建嵌套实体

时间:2018-06-16 15:53:48

标签: domain-driven-design entities aggregateroot

我有一个关于在聚合根中处理多个子实体嵌套级别的问题。

到目前为止,我只处理没有子节点的聚合根,或者最多只处理“嵌套实体的”一级“。

在创建和修改孩子时,我通过AR来管理它。使用传统的Order / OrderLines示例:

class Order:
public void addOrderLine(product, price)
public void adjustPriceForOrderLine(percentage_change, line_id)

我刚刚设计了一个具有2级嵌套的AR(都是1对多),并且很难确定通过AR处理交互的方法:

class Root:
public void addLevelOneChild(...)
public void adjustLevelOneChild(...)

但是当与嵌套在LevelOne孩子下面的孩子一起工作时,我一直采取的方法变得更加冗长。

public void addLevelTwoChildToLevelOneChild(..., levelOneChild_id)
public void adjustLevelTwoChildInLevelOneChild(..., levelOneChild_id)

有效。但是,在对二级孩子采取任何行动之前,总是需要努力确定一级孩子的本地标识符。

此外,在使用工厂方法创建新的levelOneChild时,我需要返回levelOneChild的本地ID,然后创建levelTwoChild,或者跳过一些箍来获取新的levelOneChild的本地标识。

public local_id root.addLevelOneChild(...)
public root.addLevelTwoChildtoLevelOneChild(..., local_id)

public void root.addLevelOneChild(...)
public local_id getIdforLevelOneChild(some natural identifier(s))
public root.addLevelTwoChildtoLevelOneChild(..., local_id)

这看起来是正确的做法吗?或任何有关更优雅解决方案的建议。

我一直在考虑使用自然ID(我目前正在使用guid来保持一致性)local_id,这有助于减少返回或查询生成的密钥的需要。虽然这会让持久性实现细节漏掉。

由于

3 个答案:

答案 0 :(得分:2)

你要问自己的第一件事是你是否应该拥有如此庞大的集群AR并探索将其分解。你试图保护哪些不变量?这些规则最终能否保持一致?

如果您必须拥有这个大型集群AR,请参考以下几点:

<强> 1。通用层次结构处理:

    addNode(node, parentId?)    
    removeNode(childId, parentId?)

请注意,使用异构树可能会更困难。此外,如果您将Node传递给addNode,则封装会稍微破坏,因为实体可能会被调用者修改。您可以改为传递不可变的节点描述符。

<强> 2。儿童通知父母的更改:

您可以特别允许直接与实体交互,但让他们通知AR任何更改。例如,想一想文档对象模型(DOM)和事件的冒泡。

    root.childOfId(childId).addChild(...)

    addChild(...) {
        parent.notifyAddChild(...);

        //add child
    }

第3。层次结构编辑器:

editor = root.newHierarchyEditor();

editor
    .firstChild()
    .addChild(...)
    .applyChanges(root); //could call on #1-like methods or root.editHierarchy(mutations)

请注意,无论您选择哪种方法,您都必须尽可能地保持API与您的无处不在的语言保持一致。另请注意,如果您只有2个级别的深度,那么使用您建议的显式API可能比上述任何一个更好。

答案 1 :(得分:1)

我尝试将设计保持在一个级别:具有一个或多个值对象集合的聚合根。这些值对象可以是指向另一个聚合的链接,例如,OrderLineassociative entity,在DB-parlance中,与Product聚合。

需要了解域以查看第一级子级是否应该是自己的聚合,或者这些级别子级是否提供到关联AR的链接,而后者又包含第二级值对象在你的设计中。

但是,在您的示例中的抽象/概念级别上,不可能告诉:)

我建议做一个思考实验,在你的设计中,你不允许下降到一个级别:你将如何改变你的设计?

答案 2 :(得分:1)

聚合的嵌套应仅由真正的业务不变量强制执行,除非是这种情况我喜欢将我的聚合限制为仅限于其自己的属性和值对象。

请记住,强制嵌套聚合会对性能和可伸缩性产生负面影响。

我完全建议你阅读Vaughn Vernon Effective aggregate design的三部分系列。

快乐DDDing!