代码之家  ›  专栏  ›  技术社区  ›  Michael Cook

域驱动设计:何时生成聚合根?

  •  5
  • Michael Cook  · 技术社区  · 17 年前

    我有两个相关实体,一个公司和一个供应商。我最初的想法是,公司是一个总根,供应商是公司的价值目标。所以我有一个公司的存储库,没有一个供应商的存储库。

    但当我开始构建我的应用程序时,我最终需要为供应商提供单独的列表、创建和更新表单。列表很简单,我可以打电话给公司。供应商,创建很糟糕,我可以做公司。供应商。添加(供应商),但更新让我头疼。因为我只需要一个实体,而且我不能准确地将它保存在表单之间的内存中,所以我最终需要重新蚀刻公司和所有供应商,找到需要绑定到它的实体,然后再次修改它并将其保存回数据库。

    如果我有一个供应商存储库,我真的需要做一个GetOne。我可以通过在我的公司或公司报告中添加一个GetOneSupplier来增加一些变通方法,但这似乎是垃圾。

    所以,我真的想知道它是否是一个值对象,而不是一个完整的域实体本身。

    需要单独的列表/创建/更新视图/页面是否意味着一个实体应该是它自己的根?

    2 回复  |  直到 17 年前
        1
  •  36
  •   SingleShot    17 年前

    根据您的术语,我假设您正在执行基于Eric Evans的书的DDD。听起来你已经在最初的建模过程中发现了一个问题,你是对的。

    您提到您认为供应商是 Value Object ... 我建议不是。A. 价值对象 是一种主要由其属性确定的东西。例如,日期“2009年9月30日”是一个值对象。为什么?因为具有不同月/日/年组合的所有日期实例都是不同的日期。具有相同月/日/年组合的所有日期实例都被视为相同。我们永远不会争论用我的“2009年9月30日”换你的,因为它们是一样的:-)

    Entity 另一方面,主要通过其“ID”进行标识。例如,银行账户有ID——它们都有账号。如果一家银行有两个账户,每个账户都有500美元,如果它们的账号不同,它们也是一样的。它们的属性(在本例中,它们的平衡)不能识别它们或暗示相等。我敢打赌,即使银行账户余额相同,我们也会为交换账户而争论:-)

    实体 ,我认为每个供应商主要是通过其ID而不是其属性来识别的。我自己的公司与世界上其他两家公司同名,但我们并非都可以互换。

    我认为你的建议是,如果你需要观察物体,那么它就是一个 实体 根据经验,这可能是正确的,但您应该更多地关注是什么使一个对象与其他对象不同:属性或ID。

    Aggregate Root 聚合根 (s) ??让我们从评论开始。在没有帖子的情况下发表评论有意义吗?你会创建一个评论,然后找到一个帖子并附加到它吗?如果你删除一篇文章,你会保留它的评论吗?我建议一个帖子是 聚合根 聚合根 有一个“叶子”——柱子。

    Entities 是 Aggregate Roots ,或者更好的思考方式是,它们是聚合根,每个根都没有“叶子”(无需聚合)。换句话说,公司不控制对供应商的访问或控制供应商的生命周期。它只是与供应商有一对多的关系(或者可能是多对多)。

    这使我们想到 Repositories . A. Repository 用于存储和检索 聚合根 . 您有两个(从技术上讲,它们不是聚合任何东西,但这比说“存储库存储聚合根或不是聚合中的叶子的实体”更容易),因此您需要两个 . 一个用于公司,一个用于供应商。

    我希望这有帮助。也许埃里克·埃文斯潜伏在这里,会告诉我我偏离了他的范式。

        2
  •  1
  •   Sam    17 年前

    对我来说,这听起来很简单——供应商应该有自己的存储库。如果有任何逻辑上的可能性,一个实体可以独立存在于模型中,那么它应该是一个根实体,否则你将在以后重构,这是多余的工作。

    根实体总是比值对象更灵活,尽管前面需要额外的实现工作。我发现,随着模型的发展,模型中的价值对象会随着时间的推移变得越来越少,而保留价值对象的实体通常是从第一天起就可以通过这种方式进行逻辑约束的实体。

    如果公司共享供应商,那么将供应商作为根实体也会消除数据冗余,因为您不会复制每个公司的供应商定义,而是共享引用,而且公司和供应商之间的关联也可以是双向的,这可能会产生更多的好处。