对象引用与DDD聚合中的Id引用

时间:2015-09-05 21:04:45

标签: domain-driven-design

在Pluralsight课程Domain-Driven Design Fundamentals中,有一个关于聚合物设计如何形成的例子。 该示例涉及诊所中的患者预约。这项任命有关系,例如到医生或检查室。 并且在该示例之前进行分析,得出结论:约会不应该是Doctor和ExamRoom的聚合根。 设计演变的一个步骤是从具有对象引用的Appointment到Doctor和ExamRoom对象,到保存这些其他实体的原始id,DoctorId和ExamRoomId。 他们通过以下方式激励这一变化: "通过简单地包含相关概念的ID而不是对象引用,我们能够确保当我们坚持我们的约会时,创建和更改约会对我们的系统影响最小"

我的第一个问题:这是一种常见的设计模式吗?如果我理解正确,它会推广到如下:如果对象A与对象B相关,但在A上操作永远不需要对B进行更改,则通过其id而不是B本身引用它。这是你会推荐的吗?

我的第二个问题:这与DDD有什么关系?我的意思是,约会不应该是医生的总根,并不意味着它不能保留对象引用,或者我错过了什么?

2 个答案:

答案 0 :(得分:5)

  1. 我认为这是一种常见的设计模式,至少在DDD领域是如此。埃文斯在DDD中说:
  2.   

    根是AGGREGATE的唯一成员,允许外部对象保存对

    的引用

    如果你使用像Hibernate这样的ORM,你可能不得不处理延迟加载以处理具有对象引用的深层链接对象结构。有些人认为延迟加载反模式。

    查看this QA以更好地掌握聚合的概念。就个人而言,我确信明确定义的聚合边界可以改善您的架构。

    1. 如果您实施聚合边界,您的约会类型很可能没有直接对象引用给医生。
    2. <强>更新 Vaughn Vernon谈到rules that spell out the current consensus view of DDD leaders on the style of aggregates(见第二部分):

        

      [DDD]声明一个聚合可能包含对根的引用   其他聚合。但是,我们必须记住,事实并非如此   将引用的聚合放在。的一致性边界内   一个引用它。该引用不会导致just的形成   一,整体聚合。

      他继续说道:

        

      如果要在单个事务中修改多个实例,请执行此操作   可能强烈表明您的一致性边界是错误的。   如果是这样,那可能是错过的建模机会;你的概念   无处不在的语言虽然在挥舞着,但尚未被发现   它的手和你大喊大叫(见第一部分)。

      根据我的理解,约会不应该直接引用其他聚合根,例如Doctor。

答案 1 :(得分:0)

是的,Appointment 不应该是 DoctorExamRoom 的 AR,因为这不构成正在建模的业务的最佳边界。

例如,创建预约时不应该负责验证包括医生和检查室(业务不变量/规则)的整个模型。

另外两个实体最好被建模为它们自己的独立 AR。这使系统解耦并允许三个模型单独运行,从而在同时处理所有三个模型时实现更好的并发性,例如由 3 个不同的用户同时处理 3 个不同的方面(即模型)。

还记得他们问客户是否会同时安排多人约会吗?她说不,但不排除在不久的将来,他们也会允许这样做。

这给了 Steve 和 Julie 开始简单的动机,使用域模型的初始版本在一个巨大的聚合中对所有内容进行建模......也许是故意的,所以他们后来可以为 DDD 提出两个重要点:重构和设计小聚合。

所以要回答你的第一个问题,最好让 Appointment(一个 AR)持有一个 Id 作为对 Doctor(作为一个 AR)的引用,而不是一个对象引用。< /p>

虽然持有一个对象引用起初看起来不错,因为毕竟 Doctor,在这种情况下,是一个 AR 并且被封装并负责它自己的不变量,很容易最终医生对象是不再是对外部实体的引用,而是在约会 AR 的整个部分中的实体,因为很容易开始对其调用方法并将内部 (Appointment) 逻辑链接到期望某种形式的状态一致性。

如果另一个 AR 也持有对同一医生的引用并开始做同样的事情,认为它是唯一负责该医生状态的 AR,会发生什么?好吧,您将拥有一个紧密耦合、破碎、不一致的模型。

但在一种情况下,Appointment (AR) 可以持有对 Doctor 的对象引用,如果医生被建模为内部(即的一部分)约会总量。但是外面的任何东西都不能(也不应该!)参考医生!

回答你的第二个问题,现在应该很明显了:当然它与(适当的)DDD有关。对 Appointment 的操作不应也对 Doctor 进行操作,因为这会跨越聚合边界(您在一个事务中保存多个聚合根)。那时您可能应该想到,也许当前的模型不是最好的,或者可能存在一些您尚未发现的隐藏业务规则。

但是预约可以包含对医生的引用(当然是通过 Id)。你的这部分假设是不正确的。但我想现在已经很明显了。这是第一个问题的一部分。

我在学习 DDD 时看到了这个问题,发现它是 2015 年的,它没有得到你对 @mdo 回答的第一条评论的答案,所以我想我也应该尝试回答这个问题,但尝试成为不那么简洁。也许@mdo 认为对您评论的回答也在他对您问题的回答中。我明白为什么。 DDD 令人困惑且难以掌握。我自己还在学习。无论如何,希望我做对了……对于我和其他阅读此答案的人。 ?