← Назад к вопросам

Какую проблему решает паттерн фабрика?

2.3 Middle🔥 162 комментариев
#Архитектура и паттерны#ООП

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн «Фабрика»: решаемая проблема

Основную проблему, которую решает паттерн «Фабрика» (обычно подразумевается Factory Method или Simple Factory), можно сформулировать как снижение связанности (coupling) клиентского кода с конкретными классами создаваемых объектов.

Проще говоря, паттерн инкапсулирует и централизует процесс создания объектов, скрывая от клиента детали инициализации, логику выбора конкретного типа и возможную сложность этого процесса.

Конкретные проблемы, которые устраняет «Фабрика»:

  1. Нарушение принципа открытости/закрытости (Open/Closed Principle). Без фабрики клиентский код напрямую использует оператор new для создания конкретных классов. При добавлении нового типа объекта приходится модифицировать весь код, где происходит создание.
    *   **Проблемный код (без фабрики):**
    ```php
    class OrderController {
        public function createShipment($type) {
            if ($type === 'truck') {
                $shipper = new TruckShipper();
            } elseif ($type === 'ship') {
                $shipper = new ShipShipper();
            } elseif ($type === 'plane') {
                $shipper = new PlaneShipper(); // Добавление нового типа требует правки здесь
            }
            $shipper->ship($this->order);
        }
    }
    ```
        Здесь при появлении `PlaneShipper` мы изменяем класс контроллера.

  1. Дублирование кода инициализации. Если создание объекта предполагает сложную настройку (например, конфигурацию, получение зависимостей, проверку условий), этот код будет разбросан по всему приложению.
    *   **Проблема:**
    ```php
    // В одном месте
    $logger = new FileLogger('/var/log/app.log', LogLevel::DEBUG, true);

    // В другом месте
    $logger2 = new FileLogger('/var/log/app.log', LogLevel::WARNING, true);
    // Конфигурация дублируется
    ```

3. Зависимость клиента от конкретных классов. Клиентский код становится тесно связан с именами конкретных классов (TruckShipper, FileLogger). Это затрудняет тестирование (сложно подменить реальный объект Mock-объектом) и усложняет замену одной реализации на другую в масштабах всего приложения.

  1. Централизация и сокрытие сложной логики создания. Иногда создание объекта — это не просто вызов конструктора. Может потребоваться:
    *   Выбор конкретного класса на основе конфигурации, входных данных или состояния системы.
    *   Использование пула объектов (Object Pool) или кеширования.
    *   Построение сложного графа зависимостей.

Решение через паттерн «Фабрика»:

Паттерн предлагает вынести код создания в отдельный метод или отдельный класс — фабрику. Клиент будет работать с абстракцией (интерфейсом или абстрактным классом) продукта, а фабрика — отвечать за создание конкретного экземпляра.

  • Исправленный код (с простой фабрикой):
    class ShipperFactory {
        public static function create($type): ShipperInterface {
            return match ($type) {
                'truck' => new TruckShipper(),
                'ship'   => new ShipShipper(),
                'plane'  => new PlaneShipper(), // Новая логика изолирована здесь
                default  => throw new InvalidArgumentException('Unknown shipper type'),
            };
        }
    }
    
    class OrderController {
        public function createShipment($type) {
            $shipper = ShipperFactory::create($type); // Клиент зависит только от фабрики и интерфейса
            $shipper->ship($this->order);
        }
    }
    

Какие выгоды это приносит?

  • Соблюдение OCP: Чтобы добавить поддержку нового типа Shipper, мы изменяем только класс ShipperFactory. Класс OrderController и другой клиентский код остаются неизменными.
  • Устранение дублирования: Весь код конфигурации и создания Logger находится в одном месте — в фабрике.
  • Слабая связанность: Клиент (OrderController) знает только об интерфейсе ShipperInterface и фабрике. Он не зависит от конкретных классов-грузоперевозчиков.
  • Упрощение тестирования: Фабрику можно подменить заглушкой (Mock) или стабом, возвращающим фиктивный объект для тестов. Или можно внедрить фабрику как зависимость.
  • Повышение читаемости и управляемости: Код создания объектов локализован. Логика выбора типа объекта явно выделена и названа.

Важное уточнение

В контексте PHP часто говорят о «Простых фабриках» (Simple Factory) — как в примере выше. Более сложными и гибкими вариациями являются:

  • Фабричный метод (Factory Method) — делегирует создание объектов подклассам.
  • Абстрактная фабрика (Abstract Factory) — создает семейства связанных объектов.

Итог: Паттерн «Фабрика» решает фундаментальную проблему управления созданием объектов в объектно-ориентированном дизайне. Он отделяет код, который использует объекты, от кода, который их создает, что ведет к более чистому, гибкому, тестируемому и поддерживаемому коду. В условиях роста приложения и необходимости частых изменений, использование фабрик становится практически обязательной практикой для профессионального backend-разработчика.

Какую проблему решает паттерн фабрика? | PrepBro