Разработчикам Laravel-приложений рекомендуют отказаться от использования ключевого слова new внутри контроллеров и перейти на паттерн «Фабричный метод» (Factory Method). Перенос создания объектов в специализированные фабрики делает код более расширяемым, тестируемым и поддерживаемым — эти преимущества становятся критически важными, когда проект разрастается за пределы нескольких эндпоинтов.

Почему ключевое слово new — это скрытая угроза

Когда контроллер содержит строку вида

$processor = new StripePaymentProcessor($config);

контроллер становится жестко связанным с классом StripePaymentProcessor. Каждый раз, когда требуется платежный процессор, эта строка повторяется, разбрасывая логику конструирования по всей кодовой базе. Если позже процессору понадобится логгер, менеджер кэша или другой формат конфигурации, придется обновлять каждое такое место. В результате получается хрупкий код, который сложно изменять и трудно мокать в юнит-тестах.

На помощь приходит паттерн «Фабричный метод»

Паттерн «Фабричный метод» заменяет прямое создание экземпляра методом, который возвращает объект, реализующий определенный интерфейс. Контроллер зависит от интерфейса, в то время как класс фабрики знает, какой именно конкретный класс нужно создать и как собрать его зависимости. Вся логика создания сосредоточена в одном месте, поэтому добавление новой зависимости или замена реализации затронет только фабрику.

Основные преимущества

  • Слабая связанность (Loose coupling) – контроллеры работают с абстракциями, а не с конкретными классами.
  • Централизованное создание – изменение процесса сборки требует редактирования всего одного файла.
  • Тестируемость – фабрики можно подменять заглушками (stubs) или моками (mocks), что позволяет проводить изолированные тесты контроллеров.
  • Принцип открытости/закрытости (Open/Closed Principle) – новые функции (например, новый платежный шлюз) можно добавлять, не меняя существующий код контроллера.

Аналогия с кофейней

Представьте бариста, который должен вручную молоть зерна, взбивать молоко и наливать воду для каждого заказа, используя длинную последовательность операторов if-else. Если рецепт латте изменится, каждому бариста придется заново учить шаги. Кофемашина, которая получает тип заказа и обрабатывает приготовление внутри себя, решает эту проблему: бариста просто сообщает машине, что нужно, а машина инкапсулирует все этапы. Теперь обновление рецепта означает настройку машины, а не переобучение каждого бариста.

Laravel уже активно использует фабрики

Основные компоненты самого Laravel наглядно демонстрируют работу этого паттерна:

  • Database – ConnectionFactory решает, создавать ли соединение с MySQL или PostgreSQL.
  • Queues – QueueManager создает драйверы для Redis, SQS или других бэкендов.
  • Filesystem – FilesystemManager создает экземпляры дисков local или S3.
  • Mail – MailManager разрешает (resolves) драйверы SMTP, Mailgun или другие почтовые драйверы.

Если фреймворк доверяет фабрикам в этих критически важных сервисах, пользовательский код должен следовать тому же примеру.

Когда стоит внедрять фабрику

Используйте фабрику, если:

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

Избегайте фабрики, если:

  • Конструирование — это единственный неизменяемый вызов new без дополнительной настройки.
  • Будет использоваться только одна реализация, что делает лишнюю абстракцию ненужной избыточностью.

Краткий разбор: рефакторинг контроллера платежей

  1. Определите интерфейс – PaymentProcessorInterface с методом process(array $data).
  2. Реализуйте конкретные классы – StripePaymentProcessor, PayPalPaymentProcessor, каждый из которых реализует интерфейс.
  3. Создайте фабрику – PaymentProcessorFactory с методом make(string $driver): PaymentProcessorInterface. Внутри используйте switch или массив (map) для возврата соответствующего класса, внедряя необходимые сервисы из сервис-контейнера Laravel.
  4. Внедрите фабрику – в конструкторе контроллера укажите тип PaymentProcessorFactory. Laravel разрешит её автоматически.
  5. Используйте фабрику – $processor = $this->processorFactory->make('stripe'); $processor->process($request->all());

Теперь контроллер никогда не упоминает new или конкретный процессор. Добавление нового шлюза означает создание класса и расширение карты (map) в фабрике — без изменений в контроллере.

Потенциальные недостатки и способы их минимизации

Основная критика фабрик заключается в избыточной косвенности, что может казаться излишним для тривиальных объектов. Избыточное проектирование (over-engineering) простого сервиса может раздуть кодовую базу без реальной выгоды. Ключ к решению — оценка сложности конструирования: если объект является простым хранилищем данных без зависимостей, прямое использование new может быть приемлемым. Кроме того, фабрики могут превратиться в «свалку» для несвязанной логики. Сосредоточение фабрик исключительно на создании объектов и делегирование конфигурации специализированным сервис-провайдерам помогает сохранить чистоту кода.

На что обратить внимание в дальнейшем

  • Привязки в сервис-контейнере (Service container bindings) — контейнер Laravel может автоматически разрешать фабрики, если вы привяжете интерфейс к классу фабрики в сервис-провайдере.
  • Автоматическое обнаружение (Auto-discovery) — некоторые пакеты предоставляют собственные фабрики; учитывайте возможность конфликтов имен.
  • Стратегии тестирования — при юнит-тестировании контроллеров заменяйте фабрику моком, который возвращает заглушку процессора, чтобы тесты оставались быстрыми и изолированными.

Итог

Замена разрозненных вызовов new на грамотно расположенную фабрику централизует процесс создания объектов, снижает связанность и приводит ваш код в соответствие с философией проектирования Laravel. Для команд, ожидающих роста — новых платежных провайдеров, бэкендов для хранения данных или любых компонентов плагинного типа — паттерн Factory Method является малозатратной инвестицией, которая окупается гибкостью и уверенностью. Ваше будущее «я» и любой, кто унаследует этот код, скажут вам спасибо.