Где бы вы использовали паттерн-строитель вместо абстрактной фабрики?

Я видел, как этот вопрос поднимался здесь и там несколько раз, но я так и не нашел ответа, который меня удовлетворил бы.

Из Википедии:

Builder ориентирован на пошаговое построение сложного объекта. Абстрактная фабрика подчеркивает семейство объектов продукта (простых или сложных). Builder возвращает продукт в качестве последнего шага, но что касается абстрактной фабрики, продукт возвращается немедленно.

Но для клиента это не одно и то же? Он получает полный объект после того, как он построен, поэтому для него нет дополнительных функций.

Единственный способ, которым я это вижу, - это поэтапная организация кода конструктора для создания структуры для реализации конструкторов. Что приятно, но вряд ли будет большим шагом от абстрактной фабрики.


Следующий фрагмент из Википедии является хорошим ориентиром, чтобы понять мою точку зрения:

Часто проекты начинаются с использования фабричного метода (менее сложный, более настраиваемый, подклассы множатся) и эволюционируют в абстрактную фабрику, прототип или конструктор (более гибкий, более сложный) по мере того, как дизайнер обнаруживает, где требуется большая гибкость.

Если это так, то какая сложность должна быть внесена в вашу систему, если вы перейдете от абстрактной фабрики к построителю?

Я хочу сказать, что я не могу найти пример, в котором ясно, что абстрактной фабрики будет недостаточно, и вместо этого вам понадобится Builder.


person Lino Rosa    schedule 22.12.2009    source источник
comment
+1 отличный первый вопрос, Лино! Тебе стоит почаще прыгать :-)!   -  person KLE    schedule 22.12.2009
comment
Спасибо, KLE. Хотя меня это все еще беспокоит :). Я имею в виду, что если вы строите составные объекты и убираете директора, передавая ответственность за вызов методов построителя клиентам, то это работает для меня. Только тогда строитель будет казаться идеально подходящим. Но с режиссером это не похоже ...   -  person Lino Rosa    schedule 22.12.2009
comment
@Lino Точнее, у Builder нет директора, он позволяет каждому клиенту создавать сложный продукт в соответствии со своими конкретными потребностями. Обычно два клиента Builder не создают один и тот же продукт. Если нужно создать сложный конструктор с возможностью инкапсуляции и многократного использования (директор), тогда у вас может быть метод для его инкапсуляции (и он является вашим директором). Напротив, для AbstractFactory вам обычно нужен повторно используемый Director, который создает похожие продукты (предоставляется с реализацией Factory).   -  person KLE    schedule 04.01.2010


Ответы (10)


AbstractFactory предназначен для семейства сопутствующих продуктов. Строитель рассчитан на одно изделие.

Builder предназначен для пошагового создания сложного продукта, в то время как AbstractFactory предназначен для создания абстрактным способом (то есть один раз для нескольких реализаций) менее сложного продукта.


Примеры того, что означает разница для вызывающего кода:

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

  • Конструктор позволяет передавать и проверять параметры один за другим для клиентского кода. Но он может построить конечный продукт за один шаг (например, вызов конструктора с передачей всех параметров сразу, даже сложных, которые были созданы сами). Итак, продуктом построителя может быть неизменяемый объект (или график) (что бесценно в многопоточной среде по причинам производительности и памяти).


ОБНОВЛЕНО в ответ на этот комментарий:

Lino> Но меня это все равно беспокоит :). Я имею в виду, что если вы строите составные объекты и убираете директора, передавая ответственность за вызов методов построителя клиентам, то это работает для меня. Только тогда строитель будет казаться идеально подходящим. Но с режиссером это не похоже ...

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

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

Напротив, для AbstractFactory обычно требуется многоразовый директор, который создает похожие продукты (предоставляется с реализацией Factory).

person KLE    schedule 22.12.2009
comment
Несомненно, одним из плюсов шаблона строителя является возможность повторного использования директора. Один из моих любимых примеров построителя - SAX, где многоразовый синтаксический анализатор (построитель) может использоваться с пользовательским обработчиком контента (построителем) для построения представления. Директор и строитель могут использоваться повторно независимо друг от друга. - person Theodore Norvell; 23.10.2017

Здесь уже есть несколько очень хороших ответов. Я просто предлагаю аналогию.

Допустим, вам нужен новый стол для нового офиса. Вы идете на «фабрику» и видите выбранные товары, а затем выбираете одну из полок. Если это соответствует вашим потребностям, отлично!

Теперь у вас большой офис со стенами необычной формы. Теперь вам нужен стол, форма столешницы которого соответствует вашему офису. И вы хотите, чтобы ножки подходили к остальной мебели, а также к вашему новому стулу Aeron.

Возвращаешься на тот же завод, безуспешно. Вы идете к плотнику, который может построить то, что вы хотите. Вы указываете свои спецификации и требования, а «строитель» сообщит вам об определенных ограничениях. После нескольких итераций вы получили идеальный стол!

Ладно, глупая история, но просто для облегчения: P

person o.k.w    schedule 22.12.2009

Хороший пример, когда вам нужен конструктор, - это создание чего-то по частям на основе аргументов командной строки. Например, рассмотрим конструктор с такими методами, как ...

setName()
setType()
setOption()

Строителя также можно объединить с абстрактной фабрикой, где директор просит у фабрики конкретный продукт. Опять же, это можно сделать с помощью простого фабричного шаблона, передав список аргументов в фабрику, но что, если бы аргументы были сообщениями, поступающими от сервера или клиента.

Иногда эстетика одного рисунка лучше подходит, чем эстетика другого.

person Pace    schedule 22.12.2009
comment
Опять же, это можно сделать с помощью простого фабричного шаблона, передав список аргументов в фабрику, но что, если бы аргументы были сообщениями, поступающими от сервера или клиента. Но тогда ответственность за вызов методов создания в построителях (setName, setType ...) будет передана клиентам, верно? И чтобы это сработало, соответствующие атрибуты созданных классов должны быть необязательными, иначе вы создадите несогласованный объект. Я начинаю думать, что в этом и сияет конструктор: когда вы передаете ответственность клиенту, а атрибуты необязательны - person Lino Rosa; 22.12.2009
comment
Звучит неправильно. Насколько я понимаю, паттерн Строитель состоит в том, что у вас есть директор (алгоритм построения), который выполняет все вызовы строителя (создает представление объекта) для клиента. Клиент мог выбрать своего строителя или использовать фабрику для его получения, а затем передать это директору. Затем он просто вызовет метод у директора, передающий все данные. В примере, который, как мне кажется, использовалась книга «Банда четырех», было преобразование документа в разные форматы. Также я не думаю, что сложность объекта обязательно разделяет фабрику и построитель. - person Sean Copenhaver; 23.12.2009

Builder полезен для настройки. Абстрактная фабрика полезна, когда вы не хотите, чтобы вызывающие абоненты заботились о фактической реализации. Две разные цели.

Фактически, вы можете смешивать эти два паттерна. Например, DocumentBuilderFactory в Java является классическая абстрактная фабрика: если вы прочитаете документацию, вы увидите процесс, который она использует для выбора реализации. Однако DocumentBuilder, он производит, может быть настроен позже (хотя они не следуют прототипному подходу «построителя», когда каждый метод конфигурации возвращает настраиваемый объект).

person kdgregory    schedule 22.12.2009

Builder - это инверсия управления, как и шаблон метода шаблона. Различные функции вашего бетонного строителя - это настраиваемые этапы процесса. Абстрактная фабрика - это «всего лишь» полиморфизм, когда на выходе получается вновь созданный объект. Различные функции на конкретной фабрике - это разные настраиваемые процессы, каждый из которых предположительно приводит к созданию отдельного объекта.

Итак, вам нужен строитель, когда вам нужен общий общий «сюжет» для построения ваших объектов, но с разными «сценами» внутри этого сюжета. Фабрика нужна тогда, когда между разными реализациями нет ничего общего.

Я думаю, что вы могли бы использовать и то, и другое одновременно, с абстрактной фабрикой, действующей в качестве директора в шаблоне Строителя, и каждой конкретной фабрикой, управляющей вещами по-разному. Однако это выходит за рамки «салфетки» для диаграмм UML ;-)

person Steve Jessop    schedule 22.12.2009

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

Я не уверен, что это правильное использование, но именно так я видел это и как делал это в прошлом.

person Kaleb Brasee    schedule 22.12.2009

Рассмотрим аналогию.

Вы работаете в сети ресторанов быстрого питания, где на самом деле они довольно сложны. Это не только сложно, но только определенные люди могут принять ваш заказ на определенные виды еды. Вы этого не знаете, потому что менеджер магазина решил посадить одного человека за одну кассу. Но если вы внимательно посмотрите на него, то на самом деле это продвинутая голограмма, потому что она «абстрактная». Абстрактный заказчик. Теперь, когда вы разговариваете с голограммой и размещаете заказ, компьютер с голограммой перенаправляет (полиморфизм) этот заказ на имплант в мозг человека, принимающего заказы. Имплант заставляет человека действительно пробивать в реальном регистре. Немногие из этих "конкретных" человеческих существ с управляемым разумом, которым приказывает голограмма. Теперь, когда настоящий человек вводит заказ, его отправляют на компьютер сзади, где есть сборочная линия или «строитель» для каждого типа создаваемой еды. Заказы отправляются на разные конвейеры в зависимости от человека и его кассового аппарата.

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

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

person Joshua Ramirez    schedule 24.12.2009

Для получения дополнительной информации о когда использовать шаблон Builder и его преимуществах ознакомьтесь с моим сообщением по другому аналогичному вопросу здесь

person Aaron    schedule 23.12.2009

На практике вы, вероятно, будете использовать DI + IOC, чтобы делать то, что раньше делал конструктор. К вашему сведению.

person Joshua Ramirez    schedule 27.01.2011
comment
DI и IOC предназначены для разного назначения - для слабой связи. где как Builder предоставляет интерфейс для создания сложных объектов с различным представлением. - person Brainchild; 08.01.2012

Хорошие ответы, хотел бы добавить свои в надежде, что я обнаружу, что мое понимание правильное.

Если у вас новый офис и вам нужны только новые столы, вы можете использовать Builder. Письменный стол всегда будет письменным столом, но существует множество различных конфигураций стола: размер, форма, наличие ящика, ящиков и т. Д.

Если у вас новый офис, а внутри полностью пусто, вам понадобятся различные предметы и вы бы использовали абстрактную фабрику, которая создает мебель, из которой происходит наш стол. В этом случае Desk, как мы знаем, является «сложным» объектом, поэтому он использует шаблон Builder, но здесь он является частью управляющей абстрактной фабрики. Абстрактная фабрика также может создавать простые объекты, такие как очень специфические лампы (StraightFunkyLamp), через класс StraightFunkyLampFactory.

person tehemperorer    schedule 07.03.2013