【问题标题】:Defining boundaries and communicating between aggregate roots定义边界并在聚合根之间进行通信
【发布时间】:2011-05-21 07:11:13
【问题描述】:

我可以借助一些帮助来了解我的领域模型并确保我正确地处理设计。

我有一个名为 Department 的聚合根。 Department 对象有几个子值类型,有助于定义“部门”的业务概念。在我的 UI 中,用户可以列出、创建、编辑和删除部门对象。

我有另一个名为 Project 的聚合根。一个项目有几个子值类型,但也与一个部门有关系,因为每个项目都由一个部门“拥有”。可以创建、编辑、删除项目等,这样做对部门没有影响,而删除部门也会删除它拥有的任何项目。

我的 UI 将根据当前用户有权访问的部门显示项目列表。他们可能能够访问多个部门。当同时显示为列表项和详细信息时,我需要在项目中显示部门徽标。

我的第一个想法是项目是一个聚合根,它有一个简单的 DepartmentID 属性,可用于“查找”部门。但现在我开始认为我真的只有一个聚合根:Department。

你怎么看?

更新

我不知道这是否是讨论的关键或改变了什么,但在阅读前几个答案后我想到了以下想法。

部门似乎有两种情况:

  1. 作为一个独立的实体, 支持修改。
  2. 作为一个项目的子项,其中 案例是包含只读数据和 没有行为。

这让我觉得我的模型中应该有两个“对象”,一个用于案例 #1 的聚合根和一个用于案例 #2 的值类型。我在正确的轨道上吗?

【问题讨论】:

    标签: domain-driven-design aggregateroot


    【解决方案1】:

    由于没有部门就无法存在项目,因此它可能不是聚合根。根据您的描述,听起来您只有一个 AR - 部门,用于管理其中的项目。

    如果您的行为主要是 CRUD,我不建议为它构建完整的域模型,因为您可能可以采用更简单的方法。

    更新 正如您所提到的,您可能在这里有 2 个有界上下文。一个部门是一个 AR,项目是这个 AR 的实体。在这种情况下,您将对您的部门执行操作。在第二个 BC 中,您的项目可能是 AR,部门可能是实体或 VO。这将允许您直接处理项目。

    我还建议您与您的领域专家一起研究一下,看看这些概念是否适合您的 UL,或者寻找一些可以阐明您的模型的缺失概念。我会特别寻找一个可以将项目与部门联系起来的概念。

    【讨论】:

    • 只有部门的接口/API 是 CRUD。有很多与项目相关的操作和行为,这就是我最初将其视为聚合的原因。
    • 即使项目在没有部门所有权的情况下不能“存在”,难道这也不能被视为验证规则吗?我的意思是,如果 Project 不是聚合根,那么当我的许多用例从浏览项目列表、选择项目和执行任务开始时,我必须实例化 Department 以便导航到项目针对该项目,例如编辑它的属性。我真的需要通过部门来执行此操作吗,或者在这种情况下,部门只是一个价值类型的装饰项目吗?这是我困惑的根源。
    • 如果您将它们建模为单独的 AR,然后删除一个部门,如果您还想删除项目,您将不得不使用跨 AR 的工作单元,这在某些情况下是不推荐的甚至可能是不可能的(分区、事件溯源)。我将更新答案以提供与更新部分相关的信息。
    • 如果“删除”一个部门只是设置一个标志并且没有从数据存储中物理删除记录,您的想法会改变吗?
    • 并非如此。您仍然需要在同一事务中更新标志。
    【解决方案2】:

    我认为将 Project 和 Department 都作为聚合根是完全有道理的,因为它们都是独立管理的。

    也就是说,每个项目和每个部门都有某种唯一标识符,虽然您可以将项目添加到部门,但项目本身可能已经足够复杂(具有自己的生命周期、自己的子对象等)以保证聚合根状态。

    您只需要在每个项目中保留对部门的引用即可。

    【讨论】:

    • 您的意思是“在每个项目中对部门的引用”,因为当我返回一个项目对象时,它包含对关联部门对象(及其所有子对象)的引用?让 Project 公开 DepartmentID 属性并在需要时通过其他方式查找 Department 对象会更好吗?
    • 好吧,在您的域中,您可以保留一个实际引用,或者只是一个 Guid(或其他唯一标识)属性。这取决于您在部门工作时是否总是需要访问每个项目,我认为这不太可能。只要您正确管理关系,您如何对域进行建模实际上取决于您。到目前为止,我更喜欢使用 ID。假设您的项目聚合根具有 DepartmentId 属性。然后,如果您的业务逻辑需要它,您只需通过调用 DepartmentRepository 的 GetById 方法来检索正确的部门。
    • 很多人喜欢只引用 ID。我使用休眠。 Nhibernate 有延迟加载,所以实际上我只有 id 直到我尝试访问另一个聚合,然后 NH 去获取它。这抽象了检索另一个 ag。关于您的陈述“对相关部门对象(及其所有子对象)的引用”,我认为如果您要维护对实际对象的引用,那么您必须使用某种形式的延迟加载。否则,您将在很短的时间内检索一个对象并最终在内存中获得整个系统对象图。
    【解决方案3】:

    几个简单的问题需要回答:

    1) 部门域对象可以在没有项目域对象的情况下独立存在。 - 如果是,那么部门就是一个集合体。

    2) Project 域对象是否可以独立存在 - 如果是,那么 Project 也是一个聚合

    3) 项目是否与一个部门有关系 - 那么它应该是作为财产部门公开的项目聚合的一部分

    4) 部门是否与一个或多个项目对象有关系 - 项目聚合应该是部门聚合对象的一部分。

    因此,使用 Department 聚合对象,您可能需要访问 Project(s) 对象的列表,一旦您拥有 Project 对象,您可能需要访问 Department 对象。这是一个循环引用,已经过时了。

    这是一个典型的例子,员工有一个经理,经理有一个员工列表

    【讨论】:

    • 所有 4 个问题都是。你会如何处理人际关系? Project 的 Department 属性是引用实际的 Department 对象还是代表 Project 上下文中的部门的轻量级值对象?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 2017-08-27
    相关资源
    最近更新 更多