理解域驱动设计 (DDD) 中的聚合和聚合根的问题

A problem with understanding aggregates and aggregate roots in Domain Driven Design (DDD)

我遇到了一个问题:"I can't split my domain models into aggregate roots"。

我是 DDD 的初级开发人员和新手。很想看懂,但是有时候真的很迷茫

从这里开始,我想简要描述一下我的领域。

我的项目致力于为用户提供自己创建任何类型文档的机会。用户可以创建一种新型文档。每个新类型都包含其属性。然后,此应用程序的用户可以根据其类型创建具体的文档。用户还可以发送文档以供审批。每种类型的审批流程都不同。

所以,我们有以下模型:

  1. DocumentType/ DocumentTemplate - 充当基于其的模板 具体文件被创建。它与 文件.
  2. DocumentsAttribute - 表示文档的属性。 它与 DocumentType 具有多对多关系。
  3. AttributeValue - 创建具体文档时,它查看 它的类型并为属性创建值,它具有 它的类型。与文档和属性的多对多关系。
  4. 文档 - 表示用户创建的具体文档。

还有其他模型,但我认为它们没有意义。

如您所知,我在这里应用数据模型的实体属性值 (EAV) 模式。您可以看到 diagram 显示数据库中的关系。

我的问题是:

我的模型中有很多实体,除了我描述的。

我认为 Document 绝对是我域中的聚合根。因为像ApprovalProcess这样聚合的东西是活不下去的。

这是第一个问题:

ApprovalProcess 由其步骤组成。每个步骤都是一个实体,因为它是可变的。步骤具有可以更改的状态。 ApprvalProcess 的状态取决于它的步骤。这里我们有一个业务不变量:"ApprovalProcess can be approved only if all its steps is approved".

我认为它是一个聚合根,因为它具有业务不变性并且包含无法脱离它的实体。我们不想允许直接访问其步骤以保持 ApprovalProcess 的一致性。

我是不是误认为ApprovalProcess是聚合根?它可能只是一个聚合? 一个聚合根可以存在于另一个聚合根中吗?这是否意味着 ApprovalProcess 只是聚合,因为 Document 负责访问其部分?但是当ApprovalProcess的步骤被批准时,Document委托给ApprovalProcess一个操作。

例如:

Document doc = new Document(...);
doc.SendForAooroval(); //ApprovalProcess is created.

doc.ApproveStep(int stepId); // Inside the method Document delegates responsibility for approvement to ApprovalProcess.

或者我应该将 Document 和 ApprovalProcess 分开。因此,Document 将通过 Identity 引用 ApprovalProcess。我们有以下场景:

Document doc = documentRepository.Get(docId);
doc.SendForAooroval();// A domain event "DocumentCreatedEvent" is raised.

DocumentCreatedEventHandler:

ApprovalProcess approvalProcess = new ApprovalProcess(event.DocId); // ApprovalProcessCreatedEvent is raised

approvalProcessRepository.Add(approvalProcess);
approvalProcessRepositroy.UnitOfWork.Save(); //commit 

但是如果 ApprovalProcess 的状态发生变化,Document 的状态也会发生变化。 ApprovalProcess 获得批准,然后 Document 也获得批准。另一个词 ApprovalProcess 是文档状态的一部分。多亏了它,我们才能知道Document被批准了。

我遇到的最大问题:

DocumentType 也是聚合根。它由其属性和 ApprovalScheme 组成。我还没有提到 ApprovalScheme 是为了让我的解释尽可能简单。 ApporvalScheme 也由一些实体组成。它只是 DocumentType 的批准流程。 ApprovalProcess是根据具有Document的DocumentType的ApprovalScheme创建的。没有 DocumentType 就不能存在 ApprovalScheme。一对一关系。

文档通过标识引用其文档类型。正确吗?

在开始这项任务时,我认为 DocumentType 应该是 Document 的一部分。

DocumentType 有很多文档,但在我的域中没有意义。它不代表 DocumentType 的状态。 DocumentType 可以标记为已删除但不能删除。

Document 和 DocumentType 是两个不同的聚合根。我说的对吗?

如果您阅读了,非常感谢。非常感谢您的关注和帮助! 对不起我糟糕的英语。

Am I mistaken that ApprovalProcess is an aggregate root? May it is just an aggregate? Can one aggregate root exist within another one as it's part?

这些问题对我来说没有任何意义。聚合是一组实体和值对象,其中一个实体是该组的父级。聚合根是聚合的父实体。一种特殊情况是聚合只是一个实体。单独的实体是一个聚合,实体当然是聚合根。

我想我会尝试从另一个角度对您的问题建模:作为一个状态机。

我将 ApprovalProcess 视为文档遵循的流程,而不是实体。我不知道这个过程的流程图,但我猜你所说的 "steps" 应该是一个文档在这个过程中可以有的 "states",并且你在步骤之间有转换,所以首先当您创建一个新文档时,它处于一个开始步骤,并且在文档的整个生命周期中,它从一个步骤传递到另一个步骤,直到它到达最后一个步骤(例如文档已批准)。

所以文档实体会有改变其状态的行为。

例如,在 Java 中,您可以使用枚举实现状态模式(状态机)。