Фабричный метод (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) — просто именованный способ создать объект.

Вопросы на собеседовании

  1. Где здесь полиморфизм? В переопределении метода, возвращающего Product.
  2. Может ли метод вернуть готовый общий экземпляр? Да, контракт не требует new.
  3. Обязан ли фабричный метод быть абстрактным? Нет, базовая реализация допустима.
  4. Почему Supplier<Product> иногда лучше? Он даёт композицию без наследования, если общий алгоритм не требует отдельной иерархии creator-классов.
  5. Как паттерн связан с OCP? Новый продукт подключается через новый creator, не меняя стабильный алгоритм.

Связи: Порождающие паттерны, Принципы SOLID, Шаблоны проектирования.