Абстрактный класс для строителя - PullRequest
0 голосов
/ 13 мая 2018

У меня есть классы моделей, которые всегда используют шаблон построителя, например:

public class Model {
    public static class Builder {
        private boolean isValid;
        private List<String> errorMessagesOrNull;

        public Builder setIsValid(final boolean isValid) {
            this.isValid = isValid;
            return this;
        }

        public Builder setErrorMessages(final List<String> errorMessages) {
            this.errorMessagesOrNull = errorMessages;
            return this;
        }

        public List<String> getErrorMessages() {
            return this.errorMessagesOrNull == null ? new ArrayList<>() : this.errorMessagesOrNull;
        }

        public Model Build() {
            return new Model(this);
        }
    }

    private boolean isValid;
    private List<String> errorMessages;

    private Model(final Builder builder) {
        this.isValid = builder.isValid;
        this.errorMessages = builder.getErrorMessages();
    }

    public boolean getIsValid() {
        return isValid;
    }

    public List<String> getErrorMessages() {
        return errorMessages;
    }
}

Как видите, классы моделей всегда имеют isValid и errorMessages. Я хочу написать абстрактный класс, чтобы минимизировать повторяющуюся логику для этих модельных классов.

Итак, я подошел как этот абстрактный класс:

public abstract class AbstractModel<T extends AbstractModel<T>> {

    public static abstract class Builder<T> {
        private boolean isValid;
        private List<String> errorMessagesOrNull;

        public Builder<T> setIsValid(final boolean isValid) {
            this.isValid = isValid;
            return this;
        }

        public Builder<T> setErrorMessages(final List<String> errorMessages) {
            this.errorMessagesOrNull = errorMessages;
            return this;
        }

        public List<String> getErrorMessages() {
            return this.errorMessagesOrNull == null ? new ArrayList<>() : this.errorMessagesOrNull;
        }

        public abstract T Build();
    }

    private boolean isValid;
    private List<String> errorMessages;

    private AbstractModel(final Builder<T> builder) {
        this.isValid = builder.isValid;
        this.errorMessages = builder.getErrorMessages();
    }

    public boolean getIsValid() {
        return isValid;
    }

    public List<String> getErrorMessages() {
        return errorMessages;
    }
}

Но это не совсем так, как я хотел. Когда я расширяю абстрактный класс:

public class Model extends AbstractModel<Model> {
    // Empty here since all fields are extended
}

Я не могу сделать что-то вроде:

Model model = new Model.Builder.setIsValid(true).Build();

Я хочу, чтобы у абстрактного класса был Builder статический класс, чтобы мне не нужно было писать статический класс Builder каждый раз.

Пожалуйста, сообщите.

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Вам также необходимо реализовать Builder.

public class Model extends AbstractModel<Model>{


    private Model(final Builder builder) {
        super(builder);
    }

    public static class Builder2 extends AbstractModel.Builder<Model> {

        @Override
        public Model Build() {
            return new Model(this);
        }
    }
}

, тогда можно будет позвонить

Model model = new Model.Builder2().Build();

РЕДАКТИРОВАТЬ

Такжеконструктор AbstractBuilder также должен быть protected.

  protected AbstractModel(final Builder<? extends Builder<T>> builder) {
        this.isValid = builder.isValid;
        this.errorMessages = builder.getErrorMessages();
    }
0 голосов
/ 13 мая 2018

Я думаю, что в вашей логике есть огромный недостаток.Сама программа на самом деле не имеет никакого смысла вообще.Почему вы сначала создаете Model с классом Builder?Я думаю, что лучше показать вам, как вы должны были написать свою программу, а не просто «связать» ее вместе.Хорошо, давайте начнем с класса Model.

Допустим, класс Model не может быть создан без Builder.Тогда имеет ли смысл добавить класс Builder в класс Model?Короткий ответ: нет, не будет.Вместо этого класс Builder должен содержать класс Model в качестве нестатического внутреннего класса.

/**
 * The {@code Builder} can construct new instances of the {@code Model} class.
 *
 * @see Model
 */
public class Builder
{
    private final String[] log;

    /**
     * The {@code Model} class can do something. You can only construct it through a {@code Builder}.
     *
     * @see Builder
     */
    public class Model
    {
        private final Builder builder;

        /**
         * Constructs a new {@code Model} with the specified argument.
         *
         * @param builder the {@code Builder} that constructed the model.
         */
        public Model(final Builder builder)
        {
            this.builder = builder;
        }

        /**
         * Returns the associated {@code Builder}.
         *
         * @return the builder that constructed the model.
         */
        public Builder getBuilder()
        {
            return this.builder;
        }
    }

    /**
     * Constructs a new instance of the {@code Builder} class with the specified argument.
     *
     * @param log the log of the {@code Builder}.
     */
    public Builder(final String... log)
    {
        this.log = log;
    }

    /**
     * Tries to {@code build} a new instance of the {@code Model} class.
     *
     * @return the constructed {@code Model}.
     */
    public Model build()
    {
        return new Model(this);
    }

    /**
     * Returns the log of the {@code Builder}.
     *
     * @return an log.
     */
    public String[] getLog()
    {
        return this.log;
    }

    /**
     * Determines whether or not the {@code Builder} is valid.
     *
     * @return {@code true} when the specified {@code log} is not {@code null}; {@code false} otherwise.
     */
    public boolean isValid()
    {
        return this.log != null;
    }
}

Ни один класс, кроме Builder, не может создать Model.Однако, если вы создадите новый экземпляр класса Builder и получите результат вызова метода build, у вас будет доступ ко всем public переменным и методам.

Если вы знаете, хотитечтобы создать Model, вы можете сделать это так:

Builder.Model model = new Builder().build();

Если вы не хотите использовать префикс Builder., просто добавьте оператор импорта, который импортирует класс Model.

import organisation.projectname.pathToBuilder.Builder.Model;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...