Паттерн Фабрика (factory) в javascript: примеры реализации и разбор

Зачем вообще нужен паттерн «Фабрика» в JavaScript

Паттерн Фабрика (Factory) в JavaScript - иллюстрация

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

Идея паттерна фабрика на пальцах

Паттерн Фабрика (Factory) в JavaScript - иллюстрация

Фабрика — это не магия, а обычная функция, которая возвращает нужный объект в зависимости от входных данных. Мы скрываем детали создания и оставляем наружу только понятный интерфейс. Представьте, что в приложении нужно создавать разные типы уведомлений: push, email, sms. Вместо кучи if с new EmailNotification создаётся одна фабрика createNotification(type, options), а дальше она сама решает, какой класс заинстанцировать. Такой подход особенно ценят авторы любой книги по JavaScript паттерны проектирования фабрика и практики из продакшн-проектов.

Базовый пример фабрики в JavaScript

Ниже — минимальный пример, который часто разбирают на курс JavaScript паттерны проектирования фабрика, но он вполне рабочий и в реальной жизни:


function createUser(type, data) {
  if (type === 'admin') {
    return { ...data, role: 'admin', canDelete: true };
  }
  if (type === 'manager') {
    return { ...data, role: 'manager', canApprove: true };
  }
  return { ...data, role: 'user' };
}

const admin = createUser('admin', { name: 'Ира' });

Функция createUser инкапсулирует всю логику: внешнему коду не важно, какие флаги ставятся админу или менеджеру. Если бизнес решит добавить роль "auditor", мы правим только фабрику, а не весь проект.

Паттерн фабрика в JavaScript: примеры кода из практики

Реальный кейс: интернет-магазин с тремя типами платежей — карта, PayPal, внутренний баланс. Изначально каждый обработчик создавался вручную, что породило дублирование конфигураций. После рефакторинга ввели фабрику paymentFactory, которая по типу возвращала правильный обработчик. Это позволило безболезненно добавить Apple Pay, не лазая по старому коду. Подобные паттерн фабрика в JavaScript примеры кода часто появляются в проектах, где бизнес-модель меняется каждые пару спринтов.

Кейс: фабрика обработчиков платежей


function createPaymentProcessor(type, config) {
  switch (type) {
    case 'card':
      return new CardProcessor(config.cardApiKey);
    case 'paypal':
      return new PaypalProcessor(config.paypalToken);
    case 'balance':
      return new BalanceProcessor(config.userId);
    default:
      throw new Error('Unknown payment type');
  }
}

const processor = createPaymentProcessor('card', envConfig);
processor.pay(1000);

Практический эффект: при добавлении нового провайдера меняется только фабрика и, при необходимости, конфиг. Вся остальная система видит лишь pay(), не зная, какой именно класс работает под капотом. Это снижает риск регрессии и делает код предсказуемым.

Как понять, что фабрика вам действительно нужна

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

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

Если узнаёте свой проект в этих пунктах, фабрика — хороший кандидат на внедрение, а не очередной модный паттерн ради галочки.

Практический чек-лист внедрения фабрики

Чтобы не превратить фабрику в ещё один «god object», полезно идти по шагам. Ниже — короткий план, который я обычно предлагаю разработчикам на обучение JavaScript паттерн фабрика онлайн и офлайн-сессиях. Он позволяет внедрить паттерн без болезненного рефакторинга.

  1. Выделите место, где чаще всего создаются однотипные объекты с условной логикой.
  2. Вынесите создание в отдельную функцию или модуль, не меняя интерфейс вызова.
  3. Добавьте тип (type, kind, mode) в параметры, чтобы управлять вариантом создаваемого объекта.
  4. Перенесите if / switch внутрь фабрики, а снаружи оставьте простой вызов.
  5. Покройте фабрику тестами на каждый поддерживаемый тип и ошибки.

Кейс из продакшена: фабрика логгеров

В одном проекте логирование работало через console.log, пока не понадобилось писать логи в файл и в внешнюю систему. Внедрили фабрику createLogger(env), которая возвращала нужную реализацию. На деве осталась консоль, на проде — файловый логгер плюс отправка в мониторинг. Настройки окручиваются конфигом, а бизнес-код просто вызывает logger.info(). Такой подход позже лег в основу мини-интенсива по JavaScript паттернам фабрика и другие паттерны для внутренней команды.

Типичные ошибки при использовании фабрики

Частая проблема — превращение фабрики в свалку. В неё добавляют всё подряд, не разделяя ответственность. Если фабрика начинает знать о сетевых запросах, кешировании, валидации и ещё десятке вещей, это тревожный сигнал. Адекватный подход — делать узкоспециализированные фабрики: для пользователей, платежей, логгеров, а не один универсальный “FactoryOfEverything”. При этом важно документировать контракт: что фабрика возвращает, какие типы поддерживает, какие ошибки выбрасывает.

Как лучше прокачаться в паттерне фабрика

Если хочется не просто переписать пару функций, а понять системно, как и когда применять фабрику, есть несколько рабочих путей:

  • Хорошая книга по JavaScript паттерны проектирования фабрика с конкретными сценариями и анти-примерами;
  • Короткий практический интенсив с задачами по рефакторингу кода, где фабрика реально упрощает архитектуру;
  • Собственный тестовый проект: например, мини-маркетплейс, где фабрика создаёт разные типы товаров и заказов.

Важно не заучивать определения, а обкатывать паттерн на своих задачах: логеры, нотификации, интеграции, платежи. Тогда фабрика станет естественным инструментом, а не абстрактной теорией.

Прокрутить вверх