Предоставляет интерфейс для создания семейств, связанных между собой, или независимых объектов, конкретные классы которых неизвестны.

Назначение

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

Применимость

Используйте паттерн Абстрактная фабрика, когда:

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

Результаты

Плюсы

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

Минусы:

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

Реализация

Вот некоторые полезные приемы реализации паттерна Абстрактная фабрика:

  • фабрики как объекты, существующие в единственном экземляре. Как правило, приложению нужен только один экземпляр класса конкретной фабрики на каждое семейство продуктов. Поэтому для реализации лучше всего применить паттерн Одиночка.
  • создание продуктов. Класс абстрактной фабрики объявляет только интерфейс для создания продуктов. Фактическое их создание - дело конкретных фабрик. Чаще всего для этой цели определяется Фабричный метод. Конкретная фабрика специфицирует свои продукты путем замещения фабричного метода для каждого из них. Хотя такая реализация проста, она требует создавать новый подкласс конкретной фабрики для каждого семейства продуктов, даже если они почти ничем не отличаются. Если семейств продуктов может быть много, то конкретную фабрику удастся реализовать с помощью паттерна Прототип. В этом случае она инициализируется экземпляром-прототипом каждого продукта в семействе и создает новый продукт путем клонирования этого прототипа. Подход на основе прототипов устраняет необходимость создавать новый класс конкретной фабрики для каждого нового семейства продуктов.
  • определение расширяемых фабрик. Класс абстрактной фабрики обычно определяет операции для каждого вида изготавливаемых продуктов. Виды продуктов кодируются в сигнатуре операции. Для добавления нового вида продуктов нужно изменить интерфейс класса абстрактной фабрики и всех зависящих от него классов. Более гибкий но не такой безопасный способ - добавить параметр к операциям, создающим объекты. При таком подходе классу абстрактной фабрики нужна только операция с параметром, указывающим тип создаваемого объекта. Но при такой реализации остается проблема: все продукты возвращаются клиенту одним и тем же абстрактным интерфейсом с уже определенным типом возвращаемого значения.

 Структура

Участники

AbstractFactory - абстрактная фабрика: объявляет интерфейс для операций, создающих абстрактные объекты-продукты.

ConcreteFactory - конкретная фабрика: реализует операции, создающие конкретные объекты-продукты.

AbstractProduct - абстрактный продукт: объявляет интерфейс для типа объекта-продукта.

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

Client - клиент: пользуется исключительно интерфейсами, которые объявлены в классах AbstractFactory и AbstractProduct.