【问题标题】:Aggregate root and value object outside of aggregate在聚合之外聚合根和值对象
【发布时间】:2014-03-23 11:35:16
【问题描述】:

我有一个聚合根“汽车” 汽车有一个包含“Wheel”对象的值对象“Wheels”列表。 由于没有轮子的汽车不应该存在(至少根据我们的业务逻辑),为了构建汽车,这在适当的领域驱动设计中是否有效:

double radius = 17.0;
List<Wheel> carWheels = new List<Wheel>();
carWheels.add(new Wheel(radius));
Car aCar = new Car(carWheels);

我的问题基本上是,在聚合根之外实例化值对象以构造聚合根(在构造函数中传递值对象)是否是一种好习惯。 我不想在无效状态下创建聚合根,并希望遵循最佳实践。如果上面的代码不是最佳实践,应该怎么做呢?

【问题讨论】:

    标签: domain-driven-design aggregate aggregateroot value-objects


    【解决方案1】:

    恕我直言,这既不是坏做法也不是好做法。一切都取决于您尝试建模的实际域。在某些情况下,在聚合之外创建这些 VO 可能是有意义的,而在其他情况下,它只会打开您的域以供恶意使用。 DDD 迫使您忘记一些技术问题和不良/良好做法,以便专注于实际领域:

    1. 在任何情况下制造一辆有 26 个轮子的汽车是否有意义?您的示例模型允许这样做
    2. 在任何情况下创建具有 4 个轮子的汽车是否有意义,每个轮子具有不同的半径?您的示例模型允许这样做
    3. 创建一个半径为 17.3284546 的轮子有意义吗?同样,您的模型允许这种情况发生

    因此,在我看来对于您展示的示例,在聚合本身内部处理这些不变量可能会更好,因为您可以很好地限制可以做的事情的数量汽车和车轮都被创建时。然而,这来自于对领域本身的仔细观察,而不是依赖于广为人知的好的或坏的做法。重申一下,在某些情况下,通过在聚合之外创建 VO 会更好。一切都取决于域。

    【讨论】:

    • 任何轮子的允许尺寸都可以在轮子内部进行验证。每辆车的车轮数量和配置可以在 Car 内部进行验证。这里有两个独立的验证。在应用程序的某个地方,制造 100 个车轮也可能有意义(即:一次不只是 4 个)。我接受您的回答,即这不是一个好或坏的做法,它取决于域。谢谢。
    【解决方案2】:

    我喜欢这种方法。在测试用例中,我们可以将 stub/mock Wheels 注入 Car。

    如果在制造车轮或汽车时存在复杂的业务限制,我会引入 CarFactory。

    【讨论】:

    • 谢谢。您如何看待 Wheel 内部的验证?
    • @IlanY 你可能会发现一些有用的东西here
    【解决方案3】:

    在这个具体的例子中,我会给 Car 的构造函数指定半径,让它自己构建轮子。这样,您就可以从您的客户代码中隐藏实例化细节(您的聚合之外的知识较少),并且您的客户不会受到 Car 聚合内部更改的影响。

    您应该更喜欢仅在一个步骤/操作/操作中构建聚合。如果这不仅仅是一个步骤,那么您的聚合不可避免地会显示其内部结构的一些细节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-26
      • 1970-01-01
      • 2011-03-07
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 2017-09-24
      • 2010-10-22
      相关资源
      最近更新 更多