Шаблон проектирования строителя: зачем нам директор? - PullRequest
31 голосов
/ 30 ноября 2010

Недавно я наткнулся на шаблон проектирования Builder.Похоже, что разные авторы используют «шаблон Построителя» для обозначения разных вариантов, поэтому позвольте мне описать шаблон, о котором я спрашиваю.

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

 1. Add liquids.
 2. Mix well.
 3. Add dry ingredients.
 4. Mix well.
 5. Pour batter into baking pan.
 6. Bake.
 7. Return baked cake.

Для разных кексов потребуются разные реализации этих этапов, т. Е. Какие жидкости / сухие ингредиенты использовать, с какой скоростью смешивать, как долговыпекать и т. д.

Шаблон говорит, что нужно делать это так.Для каждого продукта мы создаем класс concrete builder с реализацией для каждого из вышеуказанных шагов.Все эти классы являются производными от базового класса abstract builder *1013*, который по сути является интерфейсом.Так, например, у нас будет абстрактный базовый класс CakeBaker с чисто виртуальными методами AddLiquid(), MixLiquids() и т. Д. Конкретные пекари для кекса будут конкретными подклассами, например,

class ChocolateCakeBaker : public CakeBaker {
public:
   virtual void AddLiquids()
   {
        // Add three eggs and 1 cup of cream
   }

   virtual void AddDryIngredients()
   {
       // Add 2 cups flour, 1 cup sugar, 3 tbsp cocoa powder,
       // 2 bars ground chocolate, 2 tsp baking powder
   }
      ...
      ...
};

.LemonCitrusCakeBaker также будет подклассом CakeBaker, но в его методах будут использоваться разные ингредиенты и количества.

Различные типы тортов аналогично будут подклассами абстрактного Cake базового класса.

Наконец, у нас есть класс для реализации абстрактного алгоритма.Это директор .В примере с пекарней мы можем назвать это ExecutiveBaker.Этот класс будет принимать (от клиента) конкретный объект конструктора и использовать его методы для создания и возврата желаемого продукта.

Вот мой вопрос.Почему нам нужно, чтобы директор был отделен от абстрактного конструктора?Почему бы не свернуть их в один базовый класс абстрактного построителя, сделав защищенными открытые методы исходного абстрактного построителя (и конкретные подклассы переопределяют их, как и раньше).

Ответы [ 7 ]

21 голосов
/ 15 января 2013

Основная часть шаблона Builder относится к Abstract Builder и его подклассам (конкретные конструкторы).Согласно шаблонам проектирования GoF , директор просто «уведомляет сборщика о том, что часть продукта должна быть построена», что может быть прекрасно выполнено клиентом.Класс 1006 * в Java API является примером компоновщика без соответствующего директора - обычно клиентский класс «направляет» его.

Также в Effective Java и Созданиеи «Уничтожение объектов Java» , Джошуа Блох предлагает использовать шаблон построителя, и он не включает в себя директора.

9 голосов
/ 12 сентября 2016

Вариант GoF шаблона Builder НЕ имеет Builder БЕЗ Директора.В этом есть другая точка зрения, но я объясню подробнее.

Цель паттерна Builder - предоставить вам несколько способов создания одного и того же объекта.У строителя должны быть только методы, которые строят разные части объекта, но алгоритм - способ выполнения этих функций - должен заботить директора.Без директора каждый клиент должен был бы точно знать, как работает здание.Но с Директором все, что Клиент должен знать, это то, что Builder использовать в конкретном случае.

Итак, у нас есть две части:

  1. Строитель, который создаетчасти объекта по одной.Важно отметить, что для этого он сохраняет состояние созданного объекта.
  2. Директор, который контролирует выполнение функций Builder.

Теперь к сутиЯ имел в виду ранее.Часть шаблона Builder полезна в других случаях и использовалась разными поставщиками БЕЗ директора для различных целей.Конкретным примером такого использования будет Doctrine Query Builder .

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

Надеюсь, это поможет тем, кто ищет Google.

9 голосов
/ 06 декабря 2012

Если вы разделяетесь на Director и Builder, вы документируете различную ответственность за сборку продукта из набора деталей (директор) и ответственность за создание детали (конструктор).

  • Встроитель вы можете изменить способ сборки детали.В вашем случае, если AddLiquid() следует добавить сливки или молоко.
  • В директоре вы можете изменить способ сборки деталей.В вашем случае a, используя AddChocolate() вместо AddFruits(), вы получите другой торт.

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

class LightBakingSteps : public BakingSteps {
public:
    virtual void AddLiquids()
    {
        // Add milk instead of cream
    }

    virtual void AddDryIngredients()
    {
        // Add light sugar
    }

    ...
};

class ChoclateCakeBaker : public CakeBaker {
public:
     Cake Bake(BakingSteps& steps)
     {
         steps.AddLiquieds();
         steps.AddChocolate();      // chocolate instead of fruits
         return builder.getCake();
     }
}
2 голосов
/ 16 сентября 2014

Допустим, вы хотите сделать торт без сухих ингредиентов.То, что вы собираетесь сделать, это просто добавить новый метод в директора или создать другого директора.Это защитит вас от сложности наследования, а также сделает ваш код более гибким.

0 голосов
/ 14 сентября 2016

Строитель знает, как делать определенные шаги. Директор знает, как собрать все это, используя шаги строителя.

Они работают вместе.

Единственная уязвимость, которую я вижу в этом шаблоне, заключается в том, что клиент может вызывать методы Builder напрямую без Director - это может вызвать некоторые проблемы и несогласованность (например, не вызывать метод Init, являющийся частью целого алгоритма)

0 голосов
/ 06 декабря 2012

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

На мой взгляд, между тортом и знанием того, как его приготовить, слишком много связи.Их можно отделить, внедрив идею торта, имеющего рецепт в нашем коде (больше похоже на заимствование из реального мира, проектирование нашей модели в бизнес-сфере).Рецепт должен содержать ингредиенты и этапы выпекания (просто название шага, а не фактическая реализация, потому что рецепты не выпекают пирожные) о том, как приготовить торт, как описано в рецепте.У нашего пекаря был бы метод BakeCake (рецепт) и несколько небольших методов в соответствии с шагами выпечки, такими как смешивание, добавление ингредиентов и т. П.пекарь, вам также нужно отделить знания о приготовлении выпечки из самого пекаря тоже.Это можно сделать, представив идею, что у шеф-повара есть навык.

0 голосов
/ 30 ноября 2010

Я согласен с вами.Я думаю, что другой подход заключается в том, что CakeBaker должен иметь метод GetCake (), который возвращает метод cake (класс Cake) и метод MakeCake (), в котором будет работать алгоритм.Это хорошо, но с другой стороны, там есть ответственное разделение.Рассматривайте абстрактного конструктора и специальных компонентов как строителей частей торта, а директора - как менеджера или дизайнера, ответственного за сборку и производство торта.

...