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


183

Я читал шаблоны дизайна с веб-сайта

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

Factory - создает объекты без предоставления клиенту логики создания экземпляров и ссылается на вновь созданный объект через общий интерфейс. Это упрощенная версия Factory Method

Factory Method - определяет интерфейс для создания объектов, но позволяет подклассам решать, какой класс создавать, и ссылается на вновь созданный объект через общий интерфейс.

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

Я также посмотрел другие потоки stackoverflow, касающиеся абстрактной фабрики и фабричного метода, но нарисованные там диаграммы UML делают мое понимание еще хуже.

Может кто-нибудь, пожалуйста, скажите мне

  1. Чем эти три модели отличаются друг от друга?
  2. Когда использовать что?
  3. А также, если возможно, какие-либо примеры Java, связанные с этими шаблонами?

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

Ответы:


252

Все три типа Factory делают одно и то же: они «умный конструктор».

Допустим, вы хотите иметь возможность создавать два вида фруктов: яблоко и апельсин.

завод

Фабрика «исправлена», так как у вас есть только одна реализация без подклассов. В этом случае у вас будет такой класс:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Вариант использования: Построить Apple или Orange слишком сложно, чтобы справиться с ним в конструкторе.

Заводской метод

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

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

... тогда вы можете повторно использовать общую функциональность FruitPicker.pickFruit(), реализуя метод фабрики в подклассах:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Абстрактная Фабрика

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

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}

8
+1 Это ответ, который больше всего похож на мое понимание этих шаблонов. Добавление примеров вызова кода (клиент) также поможет? Вопрос, который меня очень беспокоит: можем ли мы сказать, что Abstract Factory Pattern - это просто Factory, расширенный с помощью Factory Method Pattern (если это правда, я проясню эту тему)?
croraf

9
Это пример, который я искал годами.
Тазтинго

Это фантастическое объяснение! Спасибо!
Андре Андраде

@ AndréAndrade Как вызвать фабричный метод ? Небольшой код, пожалуйста. Это избавит меня от сомнений по поводу его использования
Арнаб Датта

25
  1. Чем эти три модели отличаются друг от друга?

Фабрика: создает объекты, не раскрывая логику реализации клиенту.

Фабричный метод: Определите интерфейс для создания объекта, но пусть подклассы решают, какой класс создать. Метод Factory позволяет классу откладывать создание экземпляров для подклассов

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

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

  1. Когда использовать что?

Фабрика: Клиенту просто нужен класс, и ему все равно, какую конкретную реализацию он получает.

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

AbstactFactory: когда вашей системе необходимо создать несколько семейств продуктов или вы хотите предоставить библиотеку продуктов без раскрытия деталей реализации.

Абстрактные фабричные классы часто реализуются с помощью фабричного метода. Заводские методы обычно вызываются в шаблонных методах.

  1. А также, если возможно, какие-либо примеры Java, связанные с этими шаблонами?

Фабрика и ФабрикаМетод

Намерение:

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

Диаграмма UML :

введите описание изображения здесь

Product: определяет интерфейс объектов, создаваемых методом Factory.

ConcreteProduct: реализует интерфейс продукта

Создатель: объявляет фабричный метод

ConcreateCreator: реализует метод Factory для возврата экземпляра ConcreteProduct.

Постановка задачи: Создайте Фабрику Игр, используя Фабричные Методы, которые определяют интерфейс игры.

Фрагмент кода:

Фабричный образец. Когда использовать фабричные методы?

Сравнение с другими шаблонами творчества:

  1. Проектирование начинается с использования Factory Method (менее сложный, более настраиваемый, подклассы распространяются) и развивается в сторону Abstract Factory, Prototype или Builder (более гибкий, более сложный), когда дизайнер обнаруживает, где требуется большая гибкость

  2. Абстрактные фабричные классы часто реализуются с помощью фабричных методов , но они также могут быть реализованы с использованием прототипа

Ссылки для дальнейшего чтения: Sourcemaking design-pattern


Для фабричного метода, не должно ли быть определение суперкласса?
Тони Лин

21

Factory - отдельный класс Factory для создания сложного объекта.

Пример: класс FruitFactory для создания объекта Fruit

class FruitFactory{

public static Fruit getFruit(){...}

}

Фабричный метод - вместо целого отдельного класса для фабрики, просто добавьте один метод в этот класс как фабрику.

Пример:

Calendar.getInstance() (Java's Calendar)

Абстрактный Фабричный Метод - Фабрика Фабрики

Пример: допустим, мы хотим построить завод по производству компьютерных комплектующих. Таким образом, существует несколько типов компьютеров, таких как ноутбук, настольный компьютер, сервер.

Таким образом, для каждого типа компьютера нам нужна фабрика. Таким образом, мы создаем одну фабрику высокого уровня, как показано ниже

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Теперь эти 3 снова являются фабриками. (Вы будете иметь дело с самой PartFactory, но под капотом будет отдельная реализация, основанная на том, что вы предоставили в абстрактной фабрике)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

РЕДАКТИРОВАТЬ: отредактировано, чтобы предоставить точные интерфейсы для абстрактной фабрики в соответствии с возражениями в комментариях.


1
Идея ComputerFactoryзаключается в том, что у вас есть общий интерфейс создания ( getScreen(); getKeyboard(); getDiskdrive(); ...), а не интерфейс для каждого типа компьютера, как вы предлагаете. Вы можете почувствовать проблему с дизайном, если дважды используете одно и то же слово в одном выражении: Laptop Factory.get Laptop Part ().
xtofl

Нет-нет-нет, не пишите точно сам код. Это была просто анология для понимания. Если вы хотите точный пример с интерфейсами, вот оно. Объекты: Интерфейс -> ComputerPart, Реализация -> RAM, HDD, Процессор Factory: Interface-> PartFactory. getComputerPart (String s), Реализации -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Абстрактная фабрика: ComputerType.getPartFactory («String s») Использование: new ComputerType (). GetFactory («Ноутбук»). GetComputerPart («RAM»)
Рави К

2
Я обновил ответ, чтобы позаботиться о вашей заботе. Фактически абстрактная фабрика - это не что иное, как фабричная фабрика Я привел более ранний пример только для справки (при условии, что читатели позаботятся об интерфейсах при реальной реализации). Еще спасибо за уведомление. Это всегда хорошо, чтобы улучшить. :)
Ravi K

Нет, abstract Factoryэто не фабрика фабрики ... Это abstract classили interfaceвозможность создавать объекты, которые будут реализованы / расширены различными бетонными фабриками. Смотрите принятый ответ для деталей кода. И, пожалуйста, удалите или отредактируйте свой ответ соответственно.
Julien__

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

11

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

Фабричный шаблон создает объекты на основе входных критериев, таким образом гарантируя, что вам не нужно писать код, как если бы это потом создавало этот объект, а не этот объект. Хорошим примером этого является туристический сайт. Веб-сайт о путешествиях может предоставить только информацию о поездке (рейс, поезд, автобус) или / и предоставить отели или / и предоставить туристические пакеты. Теперь, когда пользователь выбирает следующее, веб-сайт должен решить, какие объекты ему нужно создать. Должен ли он только создать объект путешествия или отель тоже.

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

Обе фабрики не имеют ничего общего друг с другом, так что это хороший дизайн, чтобы держать их на разных фабриках.

Надеюсь, теперь это ясно. Еще раз изучите веб-сайт, помня об этом примере, надеюсь, он поможет. И я очень надеюсь, что правильно представил шаблоны :).


3

За этим ответом я обращаюсь к книге «Банда четырех».

В книге нет определений «Фабрика», «Простая фабрика» и «Виртуальная фабрика». Обычно, когда люди говорят о шаблоне «Фабрика», они могут говорить о чем-то, что создает определенный объект класса (но не шаблон «строитель»); они могут или не могут ссылаться на шаблоны «Фабричный метод» или «Абстрактная фабрика». Любой может реализовать «Фабрику» так, как не хочет, потому что это не формальный термин (имейте в виду, что у некоторых людей \ компаний \ сообществ может быть свой словарный запас).

Книга содержит только определения «Абстрактная фабрика» и «Фабричный метод».

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

Фабричный метод (GOF) : определите интерфейс для создания объекта, но пусть подклассы решают, какой класс создать. Factory Method позволяет классу откладывать создание экземпляров для подклассов.

Абстрактная фабрика (GOF) : предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

Источник путаницы : часто можно назвать класс, который используется в шаблоне «Factory Method», как «Factory». Этот класс является абстрактным по определению. Именно поэтому этот класс легко назвать «Абстрактной фабрикой». Но это просто название класса; Вы не должны путать его с шаблоном "Абстрактная фабрика" (имя класса! = имя шаблона). Шаблон «Абстрактная фабрика» отличается - он не использует абстрактный класс; он определяет интерфейс (не обязательно интерфейс языка программирования) для создания частей более крупного объекта или объектов, которые связаны друг с другом или должны быть созданы определенным образом.


2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Используя Factory Method, пользователь может создать А1 или А2 AbstractProductA.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

Но у Abstract Factory, имеющей более 1 фабричного метода (например: 2 фабричных метода), используя эти фабричные методы, он создаст набор объектов / связанных объектов. Используя Abstract Factory, пользователь может создавать объекты A1, B1 объектов AbstractProductA, AbstractProductB.


0

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

Существует два распространенных способа параметризации системы по классам объектов, которые она создает. Одним из способов является создание подкласса класса, который создает объекты; это соответствует использованию шаблона Factory Method (107). Основным недостатком этого подхода является то, что он может потребовать нового подкласса только для изменения класса продукта. Такие изменения могут каскадно Например, когда создатель продукта сам создается методом фабрики, вы должны также переопределить его создателя.

Другой способ параметризации системы больше зависит от состава объекта : определите объект, который отвечает за знание класса объектов продукта, и сделайте его параметром системы. Это ключевой аспект шаблонов Абстрактная фабрика (87), Строитель (97) и Прототип (117). Все три связаны с созданием нового «фабричного объекта», в обязанности которого входит создание объектов продукта. Абстрактная фабрика имеет заводской объект, производящий объекты нескольких классов. У Builder есть объект фабрики, строящий сложный продукт постепенно, используя соответственно сложный протокол. Prototype имеет объект фабрики, создающий продукт путем копирования объекта-прототипа. В этом случае объект фабрики и прототип - это один и тот же объект, поскольку прототип отвечает за возврат продукта.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.