访问Subclassed Aggregate成员

时间:2010-11-01 13:46:10

标签: domain-driven-design aggregateroot

我知道我们不应该直接更改聚合根的子节点,而应该通过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);

这些方法中的每一种都将在其内部子集合中更新(或创建新的)注释项。这有两个明显的问题:

  1. 我们必须在aggregate-root上预先定义所有可能的IMedicalNote子类的所有可用属性。这是不可接受的,因为子类的数量保证增长,取决于我们想要捕获的医疗数据的类型,这是第一位的继承的整个点。
  2. 列表中可以有多个相同音符类型的实例。此API将失败,因为我们不能只说report.SetBloodCheckComment(comment)并期望它会更新列表中的BloodCheckNote项,因为我们允许列表中有多个BloodCheckNote项。
  3. 我仍然希望通过其聚合根保持对这些笔记的所有交互,因为它必须控制整个MedicalReport聚合是否有效保存,聚合是否不可修改,粗粒度乐观 - 并发检查,等等但是我怎么能这样做?

1 个答案:

答案 0 :(得分:4)

不知道你是否错误地解释了关于聚合根的指导(或许我做了......)。

我从未读过指导说:“聚合必须为其所有聚合对象的每个可想象的属性提供代理方法”。相反,我认为它说:“聚合控制其聚合对象的生命周期,身份和关系”。

因此,客户端要求聚合对其某个对象进行(瞬态)引用并对其执行某些操作是完全有效的。我这里没有我的DDD副本来确认措辞,但这似乎与DDD summary ebook(p53)一致,其中说:

  

root可以传递内部的瞬态引用   对象是外部的,条件是外部的   操作完成后,对象不会保留引用。

因此,在您的情况下,客户会询问MedicalReport IMedicalNote的实例,获取子类型,根据需要对它们进行操作,并在适用的情况下传回根。

正如我所说:不能肯定地说这与DDD一致,但常识说它比试图反映聚合根中每个子类型的每个属性/方法更具可扩展性和灵活性。

第h