Агрегирование корневых и экземпляров создания дочерних объектов - PullRequest
2 голосов
/ 27 марта 2012

У меня есть агрегат, который включает в себя сущности A, AbstractElement, X, Y и Z. Корневой объект - A, который также имеет список AbstractElement. Объекты X, Y и Z наследуются от AbstractElement. Мне нужна возможность добавить экземпляры X, Y и Z к экземпляру A. Один из подходов состоит в том, чтобы использовать один метод для каждого типа, то есть addX, addY и addZ. Эти методы принимают в качестве аргументов значения, необходимые для создания экземпляров X, Y и Z. Но каждый раз, когда я добавляю новый тип, который наследуется от AbstractElement, мне нужно изменить сущность A, поэтому я думаю, что это не лучшее решение.

Другой подход заключается в использовании абстрактного метода добавления addAbstractElement для добавления AbstractElement экземпляров. Но в этом случае метод будет принимать в качестве аргумента экземпляр AbstractElement. Поскольку этот метод вызывается объектами, расположенными вне агрегата, в соответствии с правилами / рекомендациями DDD, разрешено ли этим внешним объектам создавать экземпляры AbstractElement? Я прочитал в книге Эрика Эванса, что внешние сущности не имеют права хранить ссылки на сущности совокупности, отличные от корня?

Какова наилучшая практика для такого рода проблем?

Спасибо

Ответы [ 2 ]

7 голосов
/ 27 марта 2012

Из книги Эвана, стр. 139:

"если вам нужно было добавить элементы в уже существующий AGGREGATE, вы можете создать МЕТОД ФАБРИКИ в корне AGGREGATE"

Это означает, что вы должны создать фабричный метод в корне (A), который будет получать детали AbstractElement. Этот метод создаст AbstractElement (X / Y / Z) в соответствии с некоторым параметром решения и добавит его во внутреннюю коллекцию AbstractElements. В конце этот метод возвращает идентификатор нового элемента.

С наилучшими пожеланиями,

Ицик Сабан

2 голосов
/ 28 марта 2012

Несколько комментариев. Как сказал предыдущий ответчик, рекомендуется использовать фабричный метод. Если вы можете избежать этого, никогда не создавайте объекты на ровном месте. Как правило, это довольно сильный запах и упущенный шанс получить больше смысла от вашего домена.

Я написал небольшой пример, чтобы проиллюстрировать это. Видео в этом случае является совокупным корнем. Внутри границ агрегата находятся видеообъект и связанные с ним комментарии. Комментарии могут быть анонимными или написаны известным пользователем (чтобы упростить пример, я представлял пользователя именем пользователя, но, очевидно, в реальном приложении у вас будет что-то вроде 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 {
    // ...      
}

Следует также обдумать, что совокупные границы содержат объекты, а не классы. Таким образом, весьма вероятно, что определенные классы (в основном объекты значений, но это также может быть и в случае сущностей) будут представлены во многих агрегатах.

...