Factory Method
Паттерн, который отвечает за вопрос «какой именно класс создать», не заставляя клиента знать про конкретные типы.
Factory Method определяет интерфейс для создания объекта, но позволяет подклассам (или конфигурации) решать, какой конкретный класс инстанцировать.
Какую задачу решает
Клиентский код хочет «транспорт», «документ», «кнопку» — но не должен зависеть от конкретного класса Truck или PdfDocument. Если разбросать if тип == "pdf": ... по всему проекту, добавление нового типа превратится в охоту по файлам. Factory Method собирает решение «что создать» в одном месте.
Идея и реализация
Заведём общий интерфейс продукта и фабричную функцию, которая по ключу возвращает нужную реализацию. Клиент работает с интерфейсом.
from abc import ABC, abstractmethod
class Transport(ABC):
@abstractmethod
def deliver(self):
...
class Truck(Transport):
def deliver(self):
return "доставка по дороге"
class Ship(Transport):
def deliver(self):
return "доставка по морю"
def create_transport(kind: str) -> Transport:
registry = {"truck": Truck, "ship": Ship}
if kind not in registry:
raise ValueError(f"неизвестный транспорт: {kind}")
return registry[kind]() # фабрика решает, какой класс создать
for kind in ("truck", "ship"):
t = create_transport(kind)
print(kind, "->", t.deliver())
Вывод:
truck -> доставка по дороге ship -> доставка по морю
Добавить самолёт — это новый класс Plane и одна строчка в registry. Клиентский цикл не меняется: он по-прежнему вызывает create_transport и deliver. Это прямое следствие принципа Open/Closed.
Класс-вариант
Каноническая (GoF) форма — фабричный метод в базовом классе, который переопределяют подклассы. Например, у Dialog есть метод create_button(), а WindowsDialog и WebDialog возвращают из него свою кнопку. В Python чаще используют функцию или регистр, как выше, — это проще и идиоматичнее.
Плюсы и минусы
| Плюсы | Минусы |
| Убирает разбросанные if по типу | Ещё один слой косвенности |
| Соблюдает OCP — новый тип не ломает клиента | Для одного-двух типов может быть избыточен |
| Изолирует логику создания | — |
Где встречается
Парсеры, выбирающие обработчик по формату файла; logging-handlers; драйверы БД, выбираемые по строке подключения; во фреймворках — создание объектов по конфигу.
Итог
- Factory Method централизует решение «какой класс создать».
- Клиент зависит от интерфейса продукта, а не от конкретных классов.
- В Python обычно реализуется функцией/регистром, а не иерархией классов.