7

我有一个系统,用户在表单中回答问题。我有代表这个模型的对象,但我不太确定如何根据 DDD 组织这些对象。

  1. 表格(有自己的列表)部分;
  2. 部分->(有自己的)组列表;
  3. 组->(有自己的)问题列表;
  4. 问题 ->(可以有自己的子问题列表)问题;
  5. 问题->(有自己的)答案列表;
  6. 答案 -> (有自己的)Answer_Details 列表;
  7. Answer_Detail ->(可能有自己的子详细信息列表)Sub_Answer_Details。

每个对象都有超过 15 个属性,如果没有父对象,每个对象都没有意义。根据 DDD,我认为 Form 实体应该是 Aggregate Root 而所有其他对象都应该是值对象。这意味着我只需要一个用于表单实体的存储库。在这种情况下,FormRepository 将被各种用于子对象的 CRUD 方法弄乱。就 DDD 而言,我的推理是否正确?我最终得到一个非常广泛的聚合体可以吗?我相信这种表示很容易导致性能问题。

4

2 回答 2

6

是的,深度层次结构在 DDD 中很好。

我最终得到一个非常广泛的聚合体可以吗?- 如果现实如此复杂,并且你的域模型是你能想到的最好的,那么你最终会得到一个复杂的聚合根。

是的,Form应该是聚合根。

所有其他对象应该是值对象- 错误,所有其他对象应该是非聚合根实体(带有 Id),没有存储库来获取它们。值对象没有 Id,值对象的相等性仅由其属性值决定,而不是由 Id 的相等性决定(更多信息here)。

在这种情况下,FormRepository 将被各种子对象的 CRUD 方法弄得一团糟——不,存储库应该只包含关于聚合根的方法,即Get<T> , Save<T> where T : IAggregateRoot,一旦你得到一个聚合根的实例,你可以遍历属性和方法来获取你需要什么。例子:

var formId = 23;
var form = _formRepository.Get(formId);
var firstGroup = form.Sections.First().Group().First();

或更好

var groupIndex = 1;
var firstGroup = form.GetGroupAt(groupIndex);

在哪里

public Group GetGroupAt(int groupIndex)
{
    Sections.First().Group().ElementAt(groupIndex);
}

我相信这种表示很容易导致性能问题- 如果您使用CQRS,您将从命令处理程序调用一些Form域方法,如果您使用 NHibernate 进行实体持久性,它将默认使用延迟加载,并且只会Form从 DB加载,然后它只会加载您真正接触过的实体,因此例如Sections.First()会从数据库加载所有部分,但不会加载组和其余部分。对于查询,您将创建一个FormDto(数据传输对象)和其他可能扁平化的 dto,以获取所需形式的数据(这可能与您的实体结构不同,UI 可能驱动 dto 结构)。查看我的博客以获取有关 DDD/CQRS/NHibernate/Repository 的信息

于 2012-11-30T15:35:51.043 回答
5

即使答案已被接受,我想我也可以加上我的 2 美分:

深层层次结构(可能)很好,但请记住聚合背后的想法实际上是为了防止这种情况发生。我倾向于按照以下方式考虑聚合中的实体:

“这个实体没有AR 有任何意义吗?”

由于我没有任何上下文 wrt 你的模型,我将使用Order/ OrderLine。没有 aOrderLine有任何意义Order吗?我可以单独对订单行做任何事情(行为)吗?这里的明显答案是“不”。

每个模型都需要根据上下文进行处理。但所有权并不一定意味着遏制

当您使用单独的有界上下文时,这些可能更容易看到,前提是您的 BC 正确:)

在您的情况下, anAnswer可能没有它的意义Question。但也许 a Questioncan live in a QuestionBankBC and a specific question may be used in your ExaminationBC and your EnrollmentBC. 所有这些都是完全编造的,所以这取决于你的上下文。

因此,如果它是Question一个 AR 案例,那么您的FormAR 拥有的问题可能只是一个值对象,甚至是一个简单的 QuestionId。

于 2012-12-04T04:34:17.297 回答