Нужен ли нам метод .build () в шаблоне Builder?

У меня возник вопрос относительно «Шаблон строителя», описанный в «Эффективной Java». Нужен ли нам .build() метод для правильной реализации паттерна? Например, предположим, что у нас есть следующий класс:

public class CoffeeDrink {

    private int numEspressoShots;
    private short milkType;
    private boolean withWhip;

    private CoffeeDrink() {
    }

    public static CoffeeDrink buildNewDrink() {
        return new CoffeeDrink();
    }

    public CoffeeDrink withEspresso(int n) {
        this.numEspressoShots = n;
        return this;
    }

    public CoffeeDrink withMilkType(shot t) {
        this.milkType = t;
        return this;
    }

    public CoffeeDrink withWhip() {
        this.withWhip = true;
        return this;
    }
}

А потом как мы его используем:

CoffeeDrink c = CoffeeDrink.buildNewDrink()
                         .withEspresso(2)
                         .withMilkType(2)
                         .withWhip();

Будет ли это все еще действительным, если у меня нет статического внутреннего класса Builder? Я предполагаю, что одно из преимуществ заключается в том, что он не создает новый объект CoffeeDrink до тех пор, пока не будет вызван метод .build(), но я все еще создаю объект Builder. Просто ищу пояснений.


person victormejia    schedule 16.01.2015    source источник
comment
Шаблон Builder используется с большим преимуществом с неизменяемыми классами. С ними Builder - это изменяемый вспомогательный класс, который помогает в окончательном построении конечного продукта, который впоследствии остается неизменным. Ваш пример представляет собой простой POJO и разделяет недостатки JavaBeans (изменчивый, может просматриваться в неполном или несовместимом состоянии и т. Д.).   -  person scottb    schedule 08.07.2016


Ответы (2)


Нет, это не шаблон Строителя. Это действительная Java, и она будет скомпилирована и запущена. Но ваш buildNewDrink() метод, независимо от того, называется он build(), buildNewDrink() или что-то еще, - это всего лишь простой фабричный метод, который создает CoffeeDrink. Эти другие методы подобны методам установки, которые возвращаются сами.

Необходим static вложенный класс Builder. Отложив создание экземпляра класса, он может выполнить логику проверки, чтобы гарантировать, что недопустимый объект не создан. Я не уверен, что есть недопустимое состояние для CoffeeDrink, поскольку оно у вас есть, но если бы оно было, с вашим кодом можно было бы создать CoffeeDrink и иметь его в недопустимом состоянии после его создания, но до вызывались другие методы. Шаблон Builder исключает эту возможность, проверяя данные перед построением экземпляра. Это также устраняет необходимость во взрыве конструктора, когда требуется множество конструкторов со всеми возможными комбинациями параметров, чтобы охватить все возможные случаи.

person rgettman    schedule 16.01.2015
comment
Я согласен с вашими замечаниями. Эти методы кажутся обычными установщиками с цепочкой. Просто незначительная деталь, но вы можете упустить not в своем ответе, поскольку в он может выполнять логику проверки, чтобы гарантировать, что недопустимый объект не создан < / я>. - person afsantos; 17.01.2015
comment
Спасибо за разъяснения. Итак, могу ли я проверить все параметры в функции построителя класса Builder, прежде чем возвращать экземпляр CoffeeDrink? - person victormejia; 17.01.2015
comment
да. Метод build() вызывается последним в цепочке. Он проверяет все ранее переданные данные, а также создает и возвращает желаемый экземпляр. - person rgettman; 17.01.2015
comment
В шаблоне Builder от GoF (Gamma et al) нет метода build(). Он действительно говорит, что ConcreteBuilders предоставляет an interface for retrieving the product, например, GetMaze(), чтобы вернуть лабиринт, который был построен поэтапно. Ни один из примеров кода в GoF не использует цепочку. Многие люди используют Builder иначе, чем GoF. Их идея заключалась в том, чтобы иметь директоров, которые инкапсулируют все этапы сборки. Идея проверки менее важна, поскольку конкретный конструктор - это не код на клиенте, а код, управляемый поставщиком API внутри директора. - person Fuhrmanator; 19.01.2015

Согласно ссылке GoF, build() не требуется. Исходная ссылка не использует цепочку, и в конце Director.construct() метода есть шаг getResult(). Класс Director заботится об инкапсуляции процесса сборки, поэтому Clients не нужно беспокоиться о том, правильно ли они строят. Это ответственность Director.

Вот диаграмма последовательности из справочника GoF на Builder:

person Fuhrmanator    schedule 19.01.2015