Подтвердить что ты не робот

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

Недавно я столкнулся с шаблоном проектирования Builder. Похоже, что разные авторы используют "шаблон 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.

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

Образец говорит, чтобы сделать это так. Для каждого продукта мы создаем конкретный класс строителя с реализацией для каждого из вышеперечисленных шагов. Все эти классы получены из базового класса абстрактного строителя, который по существу является интерфейсом. Так, например, у нас будет абстрактный базовый класс 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. Этот класс будет принимать (от клиента) конкретный объект-строитель и использовать его методы для создания и возврата желаемого продукта.

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

4b9b3361

Ответ 1

Основная часть шаблона Builder относится к абстрактному строителю и его подклассам (конкретным строителям). Согласно шаблонам дизайна GoF, директор просто "уведомляет строителя, когда должна строиться часть продукта", что может быть сделано клиентом.

Класс StringBuilder в Java API является примером строителя без соответствующего директора - обычно класс клиента "направляет" его.

Кроме того, в Эффективная Java и Создание и уничтожение объектов Java Джошуа Блох предлагает использовать шаблон конструктора, и он не включает директора.

Ответ 2

Если вы отделитесь от 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();
     }
}

Ответ 3

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

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

Итак, что мы имеем здесь, это две части:

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

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

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

Я надеюсь, что это помогает тем, кто гуглит.

Ответ 4

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

Ответ 5

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

Ответ 6

Builder знает, как выполнять определенные действия. Директор знает, как собрать все это с помощью шагов строителя.

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

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

Ответ 7

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

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

Имейте в виду, что если вам понадобится модель шеф-повара в целом, а не только пекарь торта, вам также нужно будет отделить знания о том, чтобы выпекать из самого пекаря. Это можно сделать, представив идею шеф-повара, обладающего навыками.