Шаблон строителя: почему директор строит объект?

Я изучаю шаблон Builder

В приведенной выше ссылке (пример Java) я заметил, что Builder предлагает интерфейс для создания нескольких компонентов. Наряду с их вызовом мы также вызываем getProduct().

Дело в том, что я не понимаю, почему директор должен вызывать все эти методы построения компонентов один за другим и получать результат в конце.

     /** "Director" */
 class Waiter {
    private PizzaBuilder pizzaBuilder;


public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }

public void constructPizza() {
   pizzaBuilder.createNewPizzaProduct(); 
   pizzaBuilder.buildDough(); // construct component 1
   pizzaBuilder.buildSauce(); // construct component 2
   pizzaBuilder.buildTopping();  // construct component 3
}

}

Почему бы нам не включить код построения компонентов 1, 2, 3 в сам класс ConcreteBuilder, а не в директорию, и фактически исключить слой директора.

Я понимаю, что описанный выше подход может превратить шаблон Builder во что-то другое, но я не понимаю, почему директор выполняет работу шаг за шагом. Какая польза? Если есть несколько директоров, будет дублированный код, верно? Возможно, я не понимаю мотива выполнения шаблона Builder...

ОБНОВЛЕНИЕ. Сосредотачивается ли шаблон Builder на предложении настраиваемого выбора компонентов при создании более крупного сложного объекта? В противном случае, на данный момент, я не вижу смысла вводить дополнительный слой, Директор.

Даже если это так, шаблон Decorator может быть лучшей идеей для достижения того же за счет динамической настройки компонентов. Где-то мне не хватает смысла за Builder.. :(


person phanin    schedule 09.03.2013    source источник
comment
Действительно хороший вопрос, даже после прочтения ответов я все еще не понимаю, зачем нам нужен директорский класс. Если он может обеспечить пользовательскую реализацию, тогда это имеет смысл. В противном случае нет смысла   -  person Rohit    schedule 13.10.2013


Ответы (4)


Объект конструирует не Директор, а Строитель, и он называется Продуктом. Директор существует по одной причине: чтобы пользователи класса ничего не знали о шагах, необходимых для построения объекта. Все эти разговоры о простом объединении всего в один метод — это все равно, что спрашивать, почему мы не можем превратить автомобиль в одноколесный велосипед. Мы могли бы, но а. это уже не будет машина, и б. он не сможет делать все то, что автомобили делают, чего не могут одноколесные велосипеды.

Один из лучших способов взглянуть на Builder — это слияние шаблонного метода и фабрики: нам нужен абстрактный процесс построения, чтобы мы могли поддерживать создание различных продуктов, но процесс построения включает много шагов. Идея состоит в том, что когда у вас есть архитектура Director/Builder, вы можете легко добавлять новые Builders, предоставляя новую конкретную реализацию. Это похоже на шаблонный метод, потому что Builder также может игнорировать детали семантики конструкции и просто предоставлять реализации каждой необходимой части конструкции (обратите внимание также, что некоторая логика может оказаться в абстрактной базе иерархии Builder, еще больше расширяя количество автоматических функций, которые более поздние расширители получают бесплатно).

person Rob    schedule 09.03.2013
comment
Спасибо за ответ. Должен ли шаблон Builder иметь несколько директоров? или это только один вариант использования. - person phanin; 10.03.2013
comment
Один. Режиссер разоблачает ту строчку, которую вы ищете. Сами Builders обеспечивают реализацию логики части. - person Rob; 10.03.2013
comment
Спасибо за ответ. Если есть только один Директор, т.е. только одна фиксированная пошаговая процедура создания деталей и построения объекта, то я не вижу разницы между этим шаблоном и шаблоном, кроме дополнительного слоя (Режиссер), для которого я не не вижу выгоды. Я попытался найти метод Builder vs Template, но они не были удовлетворительными. Я надеюсь, вы поняли мою точку зрения, и я извиняюсь за долгую беседу. - person phanin; 10.03.2013
comment
Чувак, шаблонный метод не является творческим шаблоном, поэтому здесь он не подходит. Директор полезен. Вас не заставляют иметь директора. Но вы все еще не понимаете. Директор — это тот, кто знает, какова последовательность построения. Строитель нет. Как вы можете говорить, что это лишнее? - person Rob; 10.03.2013

Назначение класса Director — инкапсулировать алгоритм создания объекта, т.е. отделить код логики построения от кода тех частей, которые собственно составляют объект. Без класса Director ваш класс Builder был бы более громоздким и менее модульным, поэтому его было бы сложнее поддерживать и использовать повторно.

пример из Википедии, на который вы ссылаетесь, довольно упрощен. Со сложными объектами механизм построения обычно намного сложнее, и директор не обязательно вызывает методы Builder один за другим и в том порядке, в котором они определены. Рассмотрим, например, класс Cake: он может иметь части ChocolateLayer, CreamLayer и Strawberry. Builder определяет три метода для создания этих трех частей в этом конкретном порядке, однако метод constructCake() в вашем классе Director может выглядеть примерно так:

public void constructCake() {
   CakeBuilder.createNewCakeProduct(); 
   CakeBuilder.buildChocolateLayer(); 
   CakeBuilder.buildCreamLayer(); 
   CakeBuilder.buildChocolateLayer(); // 2nd call of the same Builder method
   int totalStrawberries = 3 + new Random().nextInt(2);
   for (int i = 1; i <= totalStrawberries; i++) 
      CakeBuilder.buildStrawberry(); // put some strawberries on top
   // Please don't try this recipe at home! 
}

Что касается различий между Builder и Decorator, вы можете проверить шаблон Builder Vs Decorator< /а> вопрос.

person k29    schedule 09.03.2013
comment
Мне кажется, это правильный ответ на первоначальный вопрос. У нас может быть два директора, один будет HiltonCookDirector, другой FourSeasonsCookDirector, оба хотят построить один и тот же объект Cake (конкретный CakeBuilder будет иметь общие методы для создания своих частей), но у обоих директоров будут разные шаги, как они хотят его построить. (один хотел бы иметь двойной слой шоколада, другой слой двойного крема и т. д.). - person Tomas Bilka; 04.02.2016
comment
@TomasBilka Если вы создаете один и тот же объект разными способами, будет ли абстрактная фабрика лучшим выбором? - person Jimbo; 13.03.2016
comment
@Джимбо Да и нет. Построитель должен иметь дело со сложными объектами, которые строятся с использованием общего процесса сборки. Фабрика может построить что угодно, но не будет обращаться к абстракции общих фаз сборки для подобных объектов. - person Tomas Bilka; 20.04.2016
comment
@TomasBilka Я понял, что построитель необязательных дополнений, например, построитель запросов в популярных ORM. Абстрактная фабрика просто определяет общий интерфейс, которого фабрики должны придерживаться при создании своих объектов. Я предположил (возможно, ошибочно), что эти торты не должны иметь каждый из заданных слоев, поэтому строитель позволит добавлять дополнительные слои. - person Jimbo; 20.04.2016

Я думаю, вы неправильно поняли шаблон Builder. Вы говорите, что процесс создания различных компонентов может быть объединен в один метод, и это правда, но это не ключ к этому шаблону проектирования создания объектов. Посмотрите еще раз на этот код:

class Waiter {
    private PizzaBuilder pizzaBuilder;

    public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
    public Pizza getPizza() { return pizzaBuilder.getPizza(); }

    public void constructPizza() {
        pizzaBuilder.createNewPizzaProduct();
        pizzaBuilder.buildDough();
        pizzaBuilder.buildSauce();
        pizzaBuilder.buildTopping();
    }
}

Обратите внимание, что Waiter работает только с PizzaBuilder, он не знает, SpicyPizzaBuilder это или HawaiianPizzaBuilder, и это цель этого шаблона. В этом другом фрагменте кода:

class BuilderExample {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
        PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

        waiter.setPizzaBuilder( hawaiianPizzaBuilder );
        waiter.constructPizza();

        Pizza pizza = waiter.getPizza();

        waiter.setPizzaBuilder( spicyPizzaBuilder );
        waiter.constructPizza();

        Pizza anotherPizza = waiter.getPizza();
    }
}

вы можете увидеть, как это работает. Создается Waiter и передается сначала HawaiianPizzaBuilder, а затем SpicyPizzaBuilder, и с тем же экземпляром Waiter вы можете создать пиццу и попросить ее, и он доставит правильную. Надеюсь, я объяснил себя и что этот комментарий поможет вам ;) Удачи!!!

person ecampver    schedule 09.03.2013
comment
Привет! Большое спасибо за ответ. Чего я до сих пор не понимаю, так это того, что мы не можем позволить официанту вызывать только ConcretePizzaBuilder.createNewPizzaProduct() и позволить этому методу позаботиться о пошаговом создании компонентов и построении всего объекта?? - person phanin; 09.03.2013
comment
@phani, я понимаю, что ты имеешь в виду, и ты прав, это просто еще один способ сделать это. Вы можете использовать простой конструктор, например public Pizza(String dough, String sauce, String topping) { ... }, но он не имеет ничего общего с шаблоном конструктора, то есть, другими словами: Эй, официант, сделай мне гавайскую пиццу, а затем столичную пиццу, но не говорите мне. как, мне не нужно знать. Джаджа: Д. Надеюсь, этот комментарий поможет вам лучше понять. - person ecampver; 10.03.2013
comment
Официант на самом деле должен быть поваром. Насколько я знаю, официанты просто приносят готовую еду к столу, а не готовят (конструируют) ее. - person Tomas Bilka; 04.02.2016

Мое объяснение шаблона Builder: давайте предположим, что у нас есть объект (продукт) и для создания объекта требуется много параметров или компонентов (других объектов), теперь, что еще хуже, не все эти параметры могут потребоваться, поэтому это приведет нам либо создать много конструкторов с разными параметрами, либо ввести множество логических операторов внутри единственного конструктора, чтобы выбрать этот и отклонить этот объект, и, что еще хуже, возможно, что эти компоненты должны быть построены по порядку (в определенной последовательности) или выполните некоторую проверку бизнес-правил для них, все это сводится к сложному конструктору, который тесно связан с параметрами (компонентами) и сложен в обслуживании. Решение состоит в том, чтобы переместить эту логику в конкретный конструктор, чтобы мы получили наш объект, вызвав ConcreteBuilder.BuildComponent1(), ConcreteBuilder.BuildComponent2(), ..., ConcreteBuilder.GetMeMyObject(), но это будет тесно связано с клиентским кодом в процессе построения, каждый клиент теперь полностью осведомлен обо всех шагах, необходимых для создания нашего любимого объекта, поэтому любое изменение в процессе построения заставит нас изменить весь код клиента здесь и там, чтобы решить эту проблему, шаблон Builder вводит Director, который инкапсулирует эти шаги, и теперь все клиенты вызывают метод Build() в Режиссер, чтобы создать объект. Подводя итог, директор существует, поэтому клиентский код не знает или не тесно связан с шагами, необходимыми для создания нашего любимого объекта, теперь для чего нужны эти BuildComponent1(), BuildComponent2() методы, ну они там для решения проблем конструктора Для этого существует шаблон, о котором я упоминал в начале: теперь мы можем обеспечить порядок в процессе построения компонента, мы также можем применить бизнес-логику, уникальную для каждого конкретного конструктора внутри этих методов, мы даже можем оставить реализацию пустой для некоторые конкретные строители, потому что просто наш конечный объект (Продукт) не нуждается в этом компоненте, и теперь мы инкапсулировали этот сложный процесс построения вдали от нашего любимого объекта, который делает свою работу лучше всего, не беспокоясь о том, как построить его самостоятельно.

person Ibrahim Najjar    schedule 09.03.2013
comment
Спасибо за ответ. Пожалуйста, не могли бы вы уточнить: потому что мы хотим настроить процесс создания каждой детали. Вы имели в виду, что выбор компонентов, из которых состоит конечный продукт, можно настраивать? то есть в случае пиццы мы можем вызвать addSauce() или нет, Builder предоставляет это, но это зависит от ConcreteDirector.. - person phanin; 10.03.2013
comment
@phani, отчасти вы правы, конечный продукт можно настраивать, но не потому, что мы будем вызывать один метод, а не вызывать другой, а потому, что каждый метод составляет отдельную часть конечного продукта, поэтому мы фактически заставляем конкретных сборщиков предоставлять свои собственные уникальные нестандартные части конечного продукта, в вашем примере, разные виды пиццы с разными соусами и начинками. - person Ibrahim Najjar; 10.03.2013
comment
Спасибо за ответ. Но что я понимаю из диаграммы последовательности шаблона Builder, так это то, что клиент создает директора и настраивает его с помощью одного ConcreteBuilder, поэтому похоже, что он получает части от нескольких строителей и превращает их в один объект. это НЕ вариант использования шаблона Builder . Прошу прощения, если расширяю тему и испытываю ваше терпение.. - person phanin; 10.03.2013
comment
@phani, пожалуйста, не волнуйтесь, вы правы, что мы не собираемся смешивать Строителей вместе. я полностью изменил свой ответ, чтобы ответить на ваши последние замечания и мысли, и если вы все еще считаете необходимым спросить, пожалуйста, не стесняйтесь. - person Ibrahim Najjar; 10.03.2013