聚合根实体和子实体的实例创建

时间:2012-03-27 13:28:22

标签: domain-driven-design

我的汇总包含实体AAbstractElementXYZ。根实体是A,其中还包含AbstractElement列表。实体XYZ继承自AbstractElement。我需要将XYZ的实例添加到A的实例中。一种方法是对每种类型使用一种方法,即addXaddYaddZ。这些方法将创建XYZ的实例所需的值作为参数。但是,每次我添加一个继承自AbstractElement的新类型时,我都需要修改实体A,所以我认为这不是最好的解决方案。

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

这类问题的最佳做法是什么?

谢谢

2 个答案:

答案 0 :(得分:7)

来自Evan的书,第139页:

“如果你需要在预先存在的AGGREGATE中添加元素,你可以在AGGREGATE的根目录上创建一个FACTORY方法”

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

最诚挚的问候,

Itzik Saban

答案 1 :(得分:2)

一些评论。正如之前的回答者所说,使用工厂方法是一个好习惯。如果你可以避免它,永远不要创建对象。通常,这是一个非常大的气味,错过了从你的领域更有意义的机会。

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

以下是代码:

public class Video {
    private List<Comment> comments;

    void addComment(final Comment.Builder builder) {
        this.comments.add(builder.forVideo(this).build());
        // ...
    }
}


abstract public class Comment {
    private String username;
    private Video video;

    public static public class Builder {
        public Builder anonymous() {
             this.username = null;
             return this;
        }

        public Builder fromUser(final String username) {
             this.username = username;
             return this;
        }

        public Builder withMessage(final String message) {
             this.message = message;
             return this;
        }

        public Builder forVideo(final Video video) {
            this.video = video;
            return this;
        }

        public Comment build() {
             if (username == null) {
                 return new AnonymousComment(message);
             } else {
                 return new UserComment(username, message);
             }
        }
    }
}

public class AnonymousComment extends Comment {
    // ...
}

static public class UserComment extends Comment {
    // ...      
}

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