Фабричный метод (Factory Method)
Фабричный метод оставляет общий алгоритм в базовом типе, но переносит выбор конкретного создаваемого объекта в переопределяемый метод.
Задача и сигнал применения
Паттерн уместен, когда код умеет работать с интерфейсом продукта, но конкретная реализация зависит от варианта запуска или расширения.
- общий сценарий стабилен, меняется только один его участник;
- базовый класс не должен импортировать все реализации продукта;
- новые реализации должны добавляться без правки основного алгоритма;
- создание продукта требует полиморфного решения, а не очередного
switch.
Роли
- Product — общий контракт создаваемых объектов;
- Concrete Product — конкретная реализация;
- Creator — содержит фабричный метод и код, использующий продукт;
- Concrete Creator — переопределяет фабричный метод.
Главная деталь: Creator не обязан быть «фабрикой целиком». Обычно это класс с полезным алгоритмом, внутри которого создание является одной точкой вариативности.
Пример на Java
interface Probe { boolean isAlive(); }
abstract class HealthCheck {
protected abstract Probe createProbe();
public String run() {
Probe probe = createProbe();
return probe.isAlive() ? "UP" : "DOWN";
}
}
final class TcpHealthCheck extends HealthCheck {
private final String host;
TcpHealthCheck(String host) { this.host = host; }
@Override protected Probe createProbe() {
return () -> !host.isBlank(); // вместо реального сетевого вызова
}
}
final class ProcessHealthCheck extends HealthCheck {
private final long pid;
ProcessHealthCheck(long pid) { this.pid = pid; }
@Override protected Probe createProbe() { return () -> pid > 0; }
}run() одинаков для всех проверок. Подклассы отвечают только за создание Probe.
На практике зависимости продукта лучше передавать через конструктор creator-класса.
Компромиссы
- Creator зависит от абстракции, но для нового продукта обычно нужен новый подкласс;
- исчезает условный выбор в общем алгоритме, зато растёт иерархия типов;
- подкласс может нарушить ожидания базового класса, если контракт фабричного метода описан недостаточно точно;
- DI-контейнер нередко решает ту же задачу регистрацией реализаций без наследования.
Чем отличается
- Simple Factory — один объект выбирает реализацию через параметр; это полезный приём, но не GoF Factory Method;
- Абстрактная фабрика Abstract Factory создаёт несколько связанных продуктов;
- Строитель Builder управляет шагами и параметрами сборки;
- статическая фабрика (
of,valueOf) — просто именованный способ создать объект.
Вопросы на собеседовании
- Где здесь полиморфизм? В переопределении метода, возвращающего
Product. - Может ли метод вернуть готовый общий экземпляр? Да, контракт не требует
new. - Обязан ли фабричный метод быть абстрактным? Нет, базовая реализация допустима.
- Почему
Supplier<Product>иногда лучше? Он даёт композицию без наследования, если общий алгоритм не требует отдельной иерархии creator-классов. - Как паттерн связан с OCP? Новый продукт подключается через новый creator, не меняя стабильный алгоритм.
Связи: Порождающие паттерны, Принципы SOLID, Шаблоны проектирования.