Domain driven design 聚合子实体的根和实例创建

Domain driven design 聚合子实体的根和实例创建,domain-driven-design,Domain Driven Design,我有一个聚合,其中包括实体A,AbstractElement,X,Y和Z。根实体是A,它也有一个AbstractElement列表。实体X、Y和Z继承自AbstractElement。我需要将X、Y和Z的实例添加到A的实例中。一种方法是对每种类型使用一种方法,即addX、addY和addZ。这些方法将把创建X、Y和Z实例所需的值作为参数。但是,每次我添加继承自AbstractElement的新类型时,我都需要修改实体a,因此我认为这不是最好的解决方案 另一种方法是使用抽象add方法addAbst

我有一个聚合,其中包括实体
A
AbstractElement
X
Y
Z
。根实体是
A
,它也有一个
AbstractElement
列表。实体
X
Y
Z
继承自
AbstractElement
。我需要将
X
Y
Z
的实例添加到
A
的实例中。一种方法是对每种类型使用一种方法,即
addX
addY
addZ
。这些方法将把创建
X
Y
Z
实例所需的值作为参数。但是,每次我添加继承自
AbstractElement
的新类型时,我都需要修改实体
a
,因此我认为这不是最好的解决方案

另一种方法是使用抽象add方法
addAbstractElement
来添加
AbstractElement
实例。但是,在本例中,该方法将把
AbstractElement
的一个实例作为参数。由于此方法将由位于聚合之外的实体调用,因此遵循DDD规则/建议,这些外部实体是否有权创建
AbstractElement
的实例?我在Eric Evans的书中读到,外部实体无权持有除根以外的聚合实体的引用

针对此类问题的最佳做法是什么


感谢埃文的书,第139页:

如果需要在先前存在的聚合中添加元素,可以在聚合的根上创建工厂方法

也就是说,您应该在根(a)上创建一个工厂方法,该方法将获取AbstractElement的详细信息。此方法将根据某个决策参数创建AbstractElement(X/Y/Z),并将其添加到AbstractElements的内部集合中。最后,该方法返回新元素的id

致以最良好的祝愿


一些评论。正如前面的回答者所说,使用工厂方法是一种很好的做法。如果可以避免的话,不要突然创建对象。通常,这是一个相当大的气味和错过的机会,使更多的意义出你的领域

我写了一个小例子来说明这一点。在本例中,视频是聚合根。聚合的边界内是视频对象及其关联的注释。评论可以是匿名的,也可以是由已知用户编写的(为了简化示例,我用用户名表示用户,但很明显,在实际应用程序中,您可能会有类似于UserId的内容)

代码如下:

公开课视频{
私人名单评论;
void addComment(final Comment.Builder){
this.comments.add(builder.forVideo(this.build());
// ...
}
}
抽象公共类评论{
私有字符串用户名;
私人录像;
公共静态公共类生成器{
公共建筑商匿名(){
this.username=null;
归还这个;
}
公共生成器fromUser(最终字符串用户名){
this.username=用户名;
归还这个;
}
公共生成器withMessage(最终字符串消息){
this.message=消息;
归还这个;
}
公共视频生成器(最终视频){
这个视频=视频;
归还这个;
}
公共评论构建(){
如果(用户名==null){
返回新的匿名评论(消息);
}否则{
返回新的UserComment(用户名、消息);
}
}
}
}
公共类AnonymousComment扩展了Comment{
// ...
}
静态公共类UserComment扩展了Comment{
// ...      
}

需要考虑的一点是,聚合边界包含对象而不是类。因此,某些类(主要是值对象,但也可能是实体的情况)极有可能在许多聚合中表示。

在我的例子中,每个实体的细节都不同。要创建X的实例,我需要一个字符串。要创建Y的实例,我需要两个字符串。。。在这种情况下它是如何工作的?我怎么能只使用一种方法?DDD不限制你只创建一种方法-你可以创建3种不同的方法,只要它们作为工厂方法。但在这种情况下,我在问题中提出的问题仍然存在。每次添加新类型时,我都需要添加一个新的工厂方法。如果不使用DDD,是否可以避免每次添加新类型时都添加新的构造函数/工厂方法?如果不使用DDD,我将只有一个采用AbstractElement的方法。然后,客户机代码将实例化适当的元素X、Y或Z,并将其传递给方法。但是,DDD的一条规则是,客户端代码不应该直接实例化X、Y、Z。它应该通过位于聚合根中的方法添加它们。