EssayAI
Блог
Блог
Математика и алгоритмы

Паттерн Factory Method: пример и разбор фабричного метода

19 июня 2026Время чтения: 7 минут
#Factory Method#фабричный метод#паттерны проектирования#GoF#порождающие паттерны
Паттерн Factory Method: пример и разбор фабричного метода

Factory Method (фабричный метод) - один из самых частых порождающих паттернов GoF и при этом тот, который чаще всего путают с простой фабрикой и абстрактной фабрикой. Его суть в одной фразе: вместо прямого вызова конструктора new ConcreteProduct() мы выносим создание объекта в отдельный метод, который подклассы могут переопределить. Это позволяет добавлять новые типы продуктов, не трогая код, который ими пользуется. Разберём идею на простом примере и соберём минимальную реализацию, а ниже можно сразу собрать запрос под свою учебную задачу.

Зачем нужен фабричный метод

Представим программу, которая работает с документами: текстовый редактор открывает и сохраняет файлы разных форматов - PDF, DOCX, Markdown. Наивное решение - везде, где нужен документ, писать new PdfDocument(). Но как только появляется новый формат, приходится править десятки мест, где захардкожен конкретный класс.

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

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

Этот принцип - частное проявление более общего правила: программируй на уровне интерфейса, а не реализации. Сам паттерн относится к порождающим паттернам GoF, отвечающим за гибкое создание объектов.

Участники паттерна

В классической схеме GoF четыре роли:

  • Product (Продукт) - общий интерфейс объектов, которые создаёт фабричный метод. В примере выше это Document с методами open() и save().
  • ConcreteProduct (Конкретный продукт) - реализации этого интерфейса: PdfDocument, DocxDocument, MarkdownDocument.
  • Creator (Создатель) - класс, объявляющий фабричный метод factoryMethod(), который возвращает объект типа Product. Creator обычно содержит и основную бизнес-логику, опираясь на продукт через интерфейс.
  • ConcreteCreator (Конкретный создатель) - подкласс, переопределяющий фабричный метод, чтобы возвращать конкретный продукт.

Ключевая деталь: фабричный метод не обязан быть абстрактным. Часто Creator даёт реализацию по умолчанию, а подклассы переопределяют её только при необходимости. Главное - что создание продукта вынесено в одну переопределяемую точку.

Пример: фабричный метод на псевдокоде

Минимальная реализация в духе любого ООП-языка разбивается на две стороны. Сначала - иерархия продуктов:

  • интерфейс Document с методами open() и save();
  • классы PdfDocument и MarkdownDocument, реализующие его по-своему.

Затем - иерархия создателей:

  • абстрактный Application с методом createDocument(): Document (это и есть фабричный метод) и методом newDocument(), который вызывает фабричный метод, кладёт документ в список открытых и возвращает его;
  • PdfApplication, переопределяющий createDocument() так, что он возвращает new PdfDocument();
  • MarkdownApplication, возвращающий new MarkdownDocument().

Метод newDocument() - это бизнес-логика, общая для всех приложений. Она не знает, с каким именно документом работает: вся «развилка» спрятана в одном переопределённом методе. Чтобы переключиться на другой формат, достаточно создать новый подкласс приложения - старый код остаётся нетронутым. Это и есть принцип открытости-закрытости в действии.

Стоит проследить, как объекты связаны во время выполнения. Клиент создаёт нужный конкретный создатель - скажем, PdfApplication - и дальше зовёт у него newDocument(). Этот метод, объявленный ещё в абстрактном Application, вызывает createDocument(). Из-за позднего связывания вызывается переопределённая версия из PdfApplication, которая и возвращает PdfDocument. Клиент при этом видит результат только как Document - ему не нужно знать ни про PDF, ни про конструктор. Вся вариативность сосредоточена в одной точке расширения.

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

Factory Method против Simple Factory и Abstract Factory

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

Сравнение трёх фабрик: простая фабрика как один метод с условием, фабричный метод через наследование, абстрактная фабрика как семейство продуктов
Сравнение трёх фабрик: простая фабрика как один метод с условием, фабричный метод через наследование, абстрактная фабрика как семейство продуктов
  • Простая фабрика (Simple Factory) - это не паттерн GoF, а идиома: один метод с switch/if, который по параметру возвращает нужный объект. Удобно, но при добавлении типа приходится править сам метод.
  • Factory Method - паттерн, где выбор делается через наследование: подкласс переопределяет метод создания. Новый тип = новый подкласс, исходный код не меняется.
  • Abstract Factory (Абстрактная фабрика) - создаёт целые семейства связанных объектов (например, GUI-элементы для разных ОС: кнопка + чекбокс + окно). Внутри Abstract Factory часто использует несколько фабричных методов.

Простое правило: если нужен один продукт с выбором подкласса - это Factory Method; если нужно согласованное семейство продуктов - Abstract Factory.

Где применять на практике

Фабричный метод уместен, когда:

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

В реальных языках паттерн встречается повсеместно: Calendar.getInstance() в Java, URLConnection.openConnection(), конструкторы-фабрики в Kotlin и Swift, хуки-фабрики во многих фреймворках. Часто фабричный метод комбинируют с другими паттернами проектирования - например, Template Method вызывает фабричный метод как один из своих шагов.

Частые ошибки

  • Путают с простой фабрикой. Метод со switch по типу - это Simple Factory, а не паттерн Factory Method. В GoF выбор делается переопределением метода в подклассе, а не условием внутри одного метода.
  • Делают фабричный метод статическим. Статический метод нельзя переопределить в подклассе, а значит, теряется главный механизм паттерна - полиморфизм. Фабричный метод должен быть обычным методом экземпляра.
  • Плодят подклассы ради одного объекта. Если типов всего два и они не меняются, наследование ради фабрики избыточно - простой фабрики или параметра конструктора достаточно.
  • Возвращают конкретный тип вместо интерфейса. Если createDocument() объявлен как возвращающий PdfDocument, а не Document, теряется развязка - клиентский код снова привязан к реализации.

FAQ

Чем фабричный метод отличается от абстрактной фабрики? Factory Method создаёт один продукт и выбирает его подкласс через наследование (один переопределяемый метод). Abstract Factory создаёт целое семейство связанных продуктов и обычно содержит внутри несколько фабричных методов. Грубо: Factory Method - про один объект, Abstract Factory - про согласованный набор.

Factory Method - это то же самое, что фабрика с условием? Нет. Метод с if/switch, выбирающий класс по параметру, - это Simple Factory, идиома вне канона GoF. В настоящем Factory Method развилки нет: каждый подкласс-создатель просто возвращает свой продукт, а выбор подкласса делается на уровне типов.

К какой группе паттернов относится фабричный метод? К порождающим (creational) паттернам по классификации «Банды четырёх». Они отвечают за создание объектов так, чтобы система не зависела от того, как именно объекты создаются и компонуются.

Коротко

Factory Method выносит создание объекта в отдельный переопределяемый метод, чтобы клиентский код работал с продуктом через интерфейс, а решение о конкретном классе принимали подклассы-создатели. Это убирает жёсткую привязку new ConcreteClass(), упрощает добавление новых типов и реализует принцип открытости-закрытости. Не путайте его с простой фабрикой (метод с условием) и абстрактной фабрикой (семейство продуктов) - фабричный метод про один продукт и выбор через наследование.

Доверьте текст нейросети EssayAI

Открыть EssayAI

Бесплатно, на русском языке и без VPN

Читайте также