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