Skip to content

Паттерн Abstract Factory (абстрактная фабрика)

В этой теме мы разберем:

  • суть паттерна;
  • структуру его работы;
  • применимость и шаги реализации паттерна;
  • его отношения с другими паттернами.

Суть паттерна

Абстрактная фабрика — это порождающий паттерн проектирования, который позволяет создавать семейства связанных объектов, не привязываясь к конкретным классам создаваемых объектов.

Проблема

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

  1. Семейство зависимых продуктов. Скажем, кресло + диван + столик.
  2. Несколько вариаций этого семейства. Например, продукты кресло, диван и столик могут быть представлены в трёх разных стилях: викторианском, модерне и ар-деко.

Семейства продуктов и их вариации

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

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

Решение

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

Все вариации одного и того же объекта должны жить в одной иерархии классов

Далее ты создаешь абстрактную фабрику — общий интерфейс, который содержит методы создания всех продуктов семейства (например, создатьКресло, создатьДиван и создатьСтолик). Эти операции должны возвращать абстрактные типы продуктов, представленные интерфейсами, которые мы выделили ранее, — кресла, диваны и столики.

Конкретные фабрики соответствуют определённой вариации семейства продуктов

Как насчёт вариаций продуктов? Для каждой вариации семейства продуктов мы должны создать свою собственную фабрику, реализовав абстрактный интерфейс. Фабрики создают продукты одной вариации. Например, ФабрикаМодерн будет возвращать только КреслаМодерн, ДиваныМодерн и СтоликиМодерн.

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

Для клиентского кода должно быть безразлично, с какой фабрикой работать

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

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