我知道我们不应该直接更改聚合根的子节点,而应该通过aggregate-root上的方法来执行它们。
例如。 order.SetOrderLineQty(product, qty);
但是如果聚合根的孩子是抽象的呢? 想象一下,你有Car聚合根,它包含一个IWheel列表作为聚合的一部分。你将如何通过其聚合根添加/更改轮子的属性(谁不知道它们可能是什么样的轮子?)
更真实的例子是这样的: 医生可以创建一个MedicalRerport(聚合根),其中包含一个IMedicalNote列表(作为MedicalReport聚合的一部分)。 IMedicalNote是一个基类/接口,它被子类化为一些具体的子类,例如BloodCheckNote,TemperatureNote,MineralConcentrationNote等等。
每个子类都有不同的属性,它们都是可编辑的。 MedicalReport聚合可以包含这些注释中的一个或多个。 (每个注释子类都有一个特定的用户控件,供用户输入/更新详细信息,在大型MedicalReport屏幕下显示为面板/选项卡)
我的问题是,如何通过其聚合根(MedicalReport)严格添加/编辑这些注释的属性?由于我不允许直接更改这些注释属性,因此一个丑陋的选择是在聚合根(MedicalReport)上公开所有可能的注释属性,即:
report.SetWhiteBloodCellCount(cellCount);
report.SetBloodCheckComment(comment);
report.SetTemperature(bodyPart, temperature);
report.AddMineral(mineral, concentration);
这些方法中的每一种都将在其内部子集合中更新(或创建新的)注释项。这有两个明显的问题:
report.SetBloodCheckComment(comment)
并期望它会更新列表中的BloodCheckNote项,因为我们允许列表中有多个BloodCheckNote项。我仍然希望通过其聚合根保持对这些笔记的所有交互,因为它必须控制整个MedicalReport聚合是否有效保存,聚合是否不可修改,粗粒度乐观 - 并发检查,等等但是我怎么能这样做?
答案 0 :(得分:4)
不知道你是否错误地解释了关于聚合根的指导(或许我做了......)。
我从未读过指导说:“聚合必须为其所有聚合对象的每个可想象的属性提供代理方法”。相反,我认为它说:“聚合控制其聚合对象的生命周期,身份和关系”。
因此,客户端要求聚合对其某个对象进行(瞬态)引用并对其执行某些操作是完全有效的。我这里没有我的DDD副本来确认措辞,但这似乎与DDD summary ebook(p53)一致,其中说:
root可以传递内部的瞬态引用 对象是外部的,条件是外部的 操作完成后,对象不会保留引用。
因此,在您的情况下,客户会询问MedicalReport
IMedicalNote
的实例,获取子类型,根据需要对它们进行操作,并在适用的情况下传回根。
正如我所说:不能肯定地说这与DDD一致,但常识说它比试图反映聚合根中每个子类型的每个属性/方法更具可扩展性和灵活性。
第h