В чем разница между шаблоном проектирования Builder и шаблоном проектирования Factory?

StackOverflow https://stackoverflow.com/questions/757743

Вопрос

В чем разница между шаблоном проектирования Builder и шаблоном проектирования Factory?

Какой из них более выгоден и почему ?

Как мне представить свои результаты в виде графика, если я хочу протестировать и сравнить / противопоставить эти шаблоны?

Это было полезно?

Решение

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

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

  • Builder фокусируется на создании сложного объекта шаг за шагом.Абстрактная фабрика подчеркивает семейство объектов продукта (простое или сложное).Строитель возвращает продукт как последний шаг, но что касается абстрактной фабрики, продукт возвращается немедленно.
  • Builder часто строит Composite.
  • Часто конструкции начинаются с использованием заводского метода (менее сложного, более настраиваемого, размножения подклассов) и развиваются в сторону абстрактной фабрики, прототипа или строителя (более гибкого, более сложного), поскольку дизайнер обнаруживает, где требуется больше гибкости.
  • Иногда творческие модели дополняют друг друга:Строитель может использовать один из других шаблонов для реализации, какие компоненты создаются.Абстрактная фабрика, строителя и прототипа могут использовать Singleton в своих реализациях.

Запись в Википедии о шаблоне проектирования фабрики:http://en.wikipedia.org/wiki/Factory_method_pattern

Запись в Википедии о шаблоне проектирования строителя:http://en.wikipedia.org/wiki/Builder_pattern

Другие советы

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

Шаблон строителя, с другой стороны, по сути является объектом-оболочкой для всех возможных параметров, которые вы, возможно, захотите передать в вызов конструктора.Это позволяет вам использовать методы установки для медленного создания списка параметров.Еще одним методом класса строителя является метод build(), который просто передает объект строителя в желаемый конструктор и возвращает результат.

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

Базовый пример фабрики

// Factory
static class FruitFactory {
    static Fruit create(name, color, firmness) {
        // Additional logic
        return new Fruit(name, color, firmness);
    }
}

// Usage
Fruit fruit = FruitFactory.create("apple", "red", "crunchy");

Базовый пример строителя

// Builder
class FruitBuilder {
    String name, color, firmness;
    FruitBuilder setName(name)         { this.name     = name;     return this; }
    FruitBuilder setColor(color)       { this.color    = color;    return this; }
    FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
    Fruit build() {
        return new Fruit(this); // Pass in the builder
    }
}

// Usage
Fruit fruit = new FruitBuilder()
        .setName("apple")
        .setColor("red")
        .setFirmness("crunchy")
        .build();

Возможно, стоит сравнить примеры кода с этих двух страниц Википедии:

http://en.wikipedia.org/wiki/Factory_method_pattern
http://en.wikipedia.org/wiki/Builder_pattern

Паттерн «Фабрика» можно рассматривать как упрощенную версию паттерна «Строитель».

в Фабрика шаблон, фабрика отвечает за создание различных подтипов объекта в зависимости от потребностей.

Пользователю фабричного метода не обязательно знать точный подтип этого объекта.Пример фабричного метода createCar может вернуть Ford или Honda типизированный объект.

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

Продолжая пример с автомобилем, у вас может быть createCar метод строителя, который создает Honda-типизированный объект с 4-цилиндровым двигателем или Honda-типизированный объект с 6 цилиндрами.Шаблон Builder обеспечивает более тонкую детализацию.

Схемы обоих Шаблон строителя и Шаблон фабричного метода доступны в Википедии.

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

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

  • Построение сложного объекта шаг за шагом:шаблон строителя

  • Простой объект создается с помощью одного метода:шаблон фабричного метода

  • Создание объекта с использованием нескольких фабричных методов:Абстрактный фабричный узор

Оба являются шаблонами Творения для создания Объекта.

1) Фабричный шаблон. Предположим, у вас есть один суперкласс и N подклассов.Создание объекта зависит от того, какой параметр/значение передается.

2) Шаблон Builder – для создания сложного объекта.

Ex: Make a Loan Object. Loan could be house loan, car loan ,
    education loan ..etc. Each loan will have different interest rate, amount ,  
    duration ...etc. Finally a complex object created through step by step process.

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

Но нужно присмотреться

Этот пример из реальной жизни сделает разницу между ними более ясной.

Предположим, вы пошли в ресторан быстрого питания и заказали Еда.

1) Какая еда?

Пицца

2) Какие начинки?

Стручковый перец, помидоры, курица-барбекю, НЕТ АНАНАС

Таким образом, разные виды продуктов производятся по шаблону «Фабрика», но разные варианты (вкусы) конкретной еды создаются по шаблону «Строитель».

Различные виды продуктов питания

Пицца, Бургер, Паста

Варианты пиццы

Только сыр, сыр+помидор+стручковый перец, сыр+помидор и т. д.

Пример кода

Вы можете увидеть пример реализации обоих шаблонов здесь.
Шаблон Строителя
Заводской образец

Сначала несколько общих вещей, которые помогут следовать моей аргументации:

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

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

Отвечая на вопрос:

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

Шаблон «Абстрактная фабрика»:Правительство РФ:«Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов».

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

Шаблон «Строитель»:Правительство РФ:«Отделите построение сложного объекта от его представления, чтобы один и тот же процесс конструирования мог создавать разные представления».

Что это значит:Вы инкапсулируете процесс построения в другом классе, называемом директором (GoF).Этот директор содержит алгоритм создания новых экземпляров продукта (например.составить сложное изделие из других частей).Для создания составных частей целого продукта режиссер использует конструктор.Поменяв конструктор в директоре вы можете использовать тот же алгоритм для создания изделия, но изменить представления отдельных деталей (а значит и представление изделия).Чтобы расширить или изменить представление продукта в вашей системе, все, что вам нужно сделать, — это реализовать новый класс-построитель.

Итак, вкратце:Целью шаблона «Абстрактная фабрика» является обмен набором продуктов, предназначенных для совместного использования.Цель шаблона Builder — инкапсулировать абстрактный алгоритм создания продукта для повторного использования его для различных представлений продукта.

На мой взгляд, нельзя сказать, что паттерн «Абстрактная фабрика» — старший брат паттерна «Строитель».ДА, это оба шаблона творения, но основная цель этих шаблонов совершенно разная.

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

предположим, у нас есть машина

class Car
{
  bool HasGPS;
  bool IsCityCar;
  bool IsSportsCar;
  int   Cylenders;
  int Seats;

  public:
     void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
 };

В приведенном выше интерфейсе мы можем получить автомобиль следующим образом:

 int main()
 {
    BadCar = new Car(false,false,true,4,4);
  }

а что, если при создании мест произойдет какое-то исключение???Вы вообще не получите объект //, но

предположим, что у вас есть реализация, подобная следующей

class Car
 {
    bool mHasGPS;
    bool mIsCityCar;
    bool mIsSportsCar;
    int mCylenders;
    int mSeats;

 public:
    void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
    void SetGPS(bool hasGPs=false)  {mHasGPs = hasGPs;}
    void SetCity(bool CityCar)  {mIsCityCar = CityCar;}
    void SetSports(bool SportsCar)  {mIsSportsCar = SportsCar;}
    void SetCylender(int Cylender)  {mCylenders = Cylender;}    
    void SetSeats(int seat) {mSeats = seat;}    
};

 class CarBuilder 
 {
    Car* mCar;
public:
        CarBuilder():mCar(NULL) {   mCar* = new Car();  }
        ~CarBuilder()   {   if(mCar)    {   delete mCar;    }
        Car* GetCar()   {   return mCar; mCar=new Car();    }
        CarBuilder* SetSeats(int n) {   mCar->SetSeats(n); return this; }
        CarBuilder* SetCylender(int n)  {   mCar->SetCylender(n); return this;  }
        CarBuilder* SetSports(bool val) {   mCar->SetSports(val); return this;  }
        CarBuilder* SetCity(bool val)   {   mCar->SetCity(val); return this;    }
        CarBuilder* SetGPS(bool val)    {   mCar->SetGPS(val); return this; }
}

Теперь вы можете создавать вот так

 int main()
 {
   CarBuilder* bp =new CarBuilder;
    Car* NewCar  = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();

     bp->SetSeats(2);

     bp->SetSports(4);

     bp->SetCity(ture);

     bp->SetSports(true)

     Car* Car_II=  bp->GetCar();

  }

Во втором случае, даже если одна операция окажется неудачной, вы все равно получите Автомобиль.

Возможно, позже эта машина не будет работать идеально, но объект у вас будет.

Потому что Factory Method дает вам Car за один вызов, тогда как Builder строит один за другим.

Хотя, какой из них выбрать, зависит от потребностей дизайнера.

+-------------------------------------------------------------------+---------------------------------------------------+
|                              Builder                              |                      Factory                      |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required                                             | Interface driven                                  |
| Inner classes is involved (to avoid telescopic constructors)      | Subclasses are involved                           |
+-------------------------------------------------------------------+---------------------------------------------------+  

Шаблон телескопического конструктора

Аналогия:

  • Фабрика: Рассмотрим ресторан.Создание «сегодняшней еды» — это фабричный шаблон, потому что вы говорите кухне «принеси мне сегодняшнюю еду», и кухня (фабрика) решает, какой объект сгенерировать, основываясь на скрытых критериях.
  • Строитель: Конструктор появляется, если вы заказываете нестандартную пиццу.В этом случае официант говорит повару (строителю): «Мне нужна пицца;добавьте к нему сыр, лук и бекон!» Таким образом, конструктор раскрывает атрибуты, которые должен иметь сгенерированный объект, но скрывает, как их установить.

Учтивость

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

Строитель Характерные особенности:

  1. Шаблон Builder строит сложный объект, используя простые объекты и используя пошаговый подход.
  2. Класс Builder шаг за шагом строит конечный объект.Этот конструктор независим от других объектов
  3. Замена фабричного метода/абстрактной фабрики в этом сценарии:Слишком много аргументов для передачи из клиентской программы в класс Factory, что может привести к ошибкам.
  4. Некоторые параметры могут быть необязательными, в отличие от Factory, которая заставляет отправлять все параметры.

Фабрика (простая фабрика) существенные особенности:

  1. Творческий шаблон
  2. На основании наследства
  3. Фабрика возвращает фабричный метод (интерфейс), который, в свою очередь, возвращает конкретный объект.
  4. Вы можете заменить интерфейс новыми конкретными объектами, и клиент (вызывающая сторона) не должен знать обо всех конкретных реализациях.
  5. Клиент всегда имеет доступ только к интерфейсу, и вы можете скрыть детали создания объекта в фабричном методе.

Часто проекты начинаются с использования Фабричный метод (менее сложные, более настраиваемые, подклассы размножаются) и развиваются в направлении Абстрактная фабрика, Опытный образец, или Строитель (более гибкий, более сложный)

Посмотрите похожие посты:

Сохранение строителя в отдельном классе (свободный интерфейс)

Шаблоны проектирования:Фабрика против фабричного метода против абстрактной фабрики

Для получения более подробной информации вы можете обратиться к статьям ниже:

создание источников

журналдев

Шаблоны «Абстрактная фабрика» и «Строитель» являются шаблонами создания, но имеют разное предназначение.

Абстрактная фабрика особое внимание уделяется созданию объектов для семейств связанных объектов, где:

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

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

  • Объект Builder инкапсулирует конфигурацию сложного объекта.
  • Director Object знает протокол использования строителя, где протокол определяет все логические шаги, необходимые для создания комплексного объекта.

Сложная конструкция — это когда конструируемый объект состоит из различных других объектов, представленных абстракциями.

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

  1. Пример:Кола, Биг Мак, Картофель фри
  2. Пример:Спрайт, Наггетсы, Картошка фри

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

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

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

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

Строитель:Используется для строительства неизменный объекты, когда зависимости объекта, экземпляр которого необходимо создать, частично известны заранее, а частично предоставлены клиентом разработчика.

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

Здесь класс-строитель действует как посредник между основным классом и классами конкретных типов.Больше абстракции.

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

Я считаю, что использование и разницу между шаблонами Factory и Builder можно будет легче понять/разъяснить в определенный период времени, если вы работаете с одной и той же базой кода и меняете требования.

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

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

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

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

Пример:Допустим, мы создаем лабиринт

1.Абстрактная фабрика:

Maze* MazeGame::CreateMaze (MazeFactory& factory) {
Maze* maze = factory.MakeMaze(); /// product is available at start!!
 /* Call some methods on maze */
return maze;
}

2.Строитель:

Maze* MazeGame::CreateMaze (MazeBuilder& builder) {
builder.buildMaze(); /// We don't have access to maze
 /* Call some methods on builder */
return builder.GetMaze();
}

Модель сборки подчеркивает сложность создания объекта (решается "шагами")

Абстрактный узор подчеркивает «просто» «абстракцию» (множественных, но связанных) объектов.

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

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

ИМХО

Builder - это своего рода более сложная Фабрика.

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

Итак, говоря об эволюции "Моделей создания" по сложности, вы можете думать об этом следующим образом:

Dependency Injection Container -> Service Locator -> Builder -> Factory

Строитель и Абстрактная фабрика

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

Общий интерфейс для продуктов

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

От: http://www.oodesign.com/builder-pattern.html

Оба шаблона созданы для одной и той же необходимости:Скрыть от некоторого клиентского кода логику построения сложного объекта.Но что делает объект «сложным» (а иногда и усложняет)?В основном это связано с зависимостями или, скорее, с состоянием объекта, состоящего из более частичных состояний.Вы можете внедрить зависимости с помощью конструктора, чтобы установить начальное состояние объекта, но объекту может потребоваться много из них, некоторые из них будут находиться в исходном состоянии по умолчанию (просто потому, что мы должны были понять, что установка зависимости по умолчанию на ноль - не самый чистый способ ) и некоторые другие, установленные в состояние, обусловленное каким-либо условием.Более того, существуют свойства объекта, которые являются своего рода «незаметными зависимостями», но также могут принимать необязательные состояния.

Есть два хорошо известных способа справиться с этой сложностью:

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

  • Полиморфизм:Правила построения объявляются непосредственно в определении подтипа, поэтому у вас есть набор правил для каждого подтипа, и какое-то условие определяет, какое из этих наборов правил применимо для создания объекта.Фабрика идеально вписывается в этот сценарий.

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

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

Единственная общая тема этих двух шаблонов — сокрытие конструкторов и создания объектов за фабричными методами, а также метода сборки для улучшения построения объектов.

Шаблон «Фабрика» позволяет вам создать объект сразу, а шаблон «Построитель» позволяет прервать процесс создания объекта.Таким образом, вы можете добавлять различные функциональные возможности во время создания объекта.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top