具有深层次结构的聚合根是否适合DDD?

ddv*_*ddv 7 domain-driven-design aggregateroot

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

  1. 表格(有自己的清单)章节;
  2. 部分 - >(有自己的列表)组;
  3. 集团 - >(有自己的清单)问题;
  4. 问题 - >(可以有自己的子问题列表)问题;
  5. 问题 - >(有自己的清单)答案​​;
  6. 答案 - >(有自己的清单)Answer_Details;
  7. Answer_Detail - >(可能有自己的子细节列表)Sub_Answer_Details.

每个对象都有超过15个属性,如果没有父对象,每个属性都没有意义.根据DDD,我认为Form实体应该是Aggregate Root,所有其他对象应该是值对象.这意味着我只需要一个表单实体的存储库.在这种情况下,FormRepository将与子对象的各种CRUD方法混杂在一起.我的推理是否适合DDD?我最终得到了一个非常广泛的聚合物吗?我相信这样的表示很容易导致性能问题.

xha*_*fan 6

是的,DDD中的深层次结构很好.

我最终得到了一个非常广泛的聚合物吗? - 如果现实情况复杂,并且您的领域模型尽可能最好,那么最终会得到一个复杂的聚合根.

是的,Form应该是聚合根.

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

在这种情况下,FormRepository会混杂使用各种子对象的CRUD方法 - 不,存储库应该只包含有关聚合根的方法,即Get<T> , Save<T> where T : IAggregateRoot,一旦获得聚合根的实例,就可以遍历属性和方法来获取你需要什么.例:

var formId = 23;
var form = _formRepository.Get(formId);
var firstGroup = form.Sections.First().Group().First();
Run Code Online (Sandbox Code Playgroud)

或更好

var groupIndex = 1;
var firstGroup = form.GetGroupAt(groupIndex);
Run Code Online (Sandbox Code Playgroud)

哪里

public Group GetGroupAt(int groupIndex)
{
    Sections.First().Group().ElementAt(groupIndex);
}
Run Code Online (Sandbox Code Playgroud)

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


Ebe*_*oux 5

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

深层次结构(可能)很好,但请记住聚合背后的想法是实际上阻止这种情况.我倾向于将实体集中在以下方面:

"这个实体是否有任何意义,而不该AR?"

由于我的模型没有任何上下文,我将使用Order/ OrderLine.没有这个OrderLine有什么意义Order吗?我可以单独使用订单行做任何事情(行为)吗?这里显而易见的答案是"不".

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

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

在你的情况下,Answer没有它可能没有意义Question.但也许一个人Question可以住在QuestionBank卑诗省,一个特定的问题可能会用在ExaminationBC和你的Enrollment卑诗省.所有这些都是完全弥补的,这取决于你的背景.

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