Factory Pattern — Фабрика
Функция или объект, который создаёт другие объекты. Не из канонического GoF (это Factory Method), но в JS — повсеместный приём.
Проблема
Создание объекта со сложной инициализацией не должно повторяться в коде клиента. Конструктор класса часто недостаточен: нужна доинициализация, выбор подкласса, регистрация в коллекции.
Где используется
- Создание UI-компонентов по типу
- Парсинг данных (JSON → разные классы)
- Создание соединений (HTTP, WebSocket)
- Игровые объекты (враги, предметы)
- React.createElement — фабрика элементов
Решение
Фабрика — это более высокоуровневая абстракция, чем класс. Лестница абстракций по автору: instance → class → factory → pool.
- Объект собирается из «трэша»: литералов объектов, примесей (mixins), оберток (wrappers).
- Может быть функцией, классом, методом класса (Factory Method).
- Может доинициализировать, добавить в коллекцию, провалидировать.
Реализации
Factory Function (фабричная функция)
// Простейшая фабрика — функция, возвращающая объект
const createUser = (name, role) => ({
name,
role,
createdAt: new Date,
greet { return `Hi, ${this.name} (${this.role})`; }
});
// V8 создаст hidden class для всех users одинаковой формы
const u1 = createUser('Marcus', 'admin');
const u2 = createUser('Mark', 'user');
// Скобки — чтобы стрелка не приняла {} за блок
const make = (name, group) => ({ name, group });
const wrong = (name, group) => { name, group }; // вернёт undefined
Factory Function с приватностью через замыкание
function createCounter(initial = 0) {
let count = initial; // приватно
return {
increment { return ++count; },
decrement { return --count; },
getCount { return count; },
reset { count = initial; }
};
}
const counter = createCounter(10);
counter.increment; // 11
counter.count; // undefined — приватно
counter.getCount; // 11
Factory Method (фабричный метод)
class Notification {
constructor(message) { this.message = message; }
show { throw new Error('abstract'); }
}
class EmailNotification extends Notification {
show { console.log(`Email: ${this.message}`); }
}
class SMSNotification extends Notification {
show { console.log(`SMS: ${this.message}`); }
}
class NotificationFactory {
static create(type, message) {
switch (type) {
case 'email': return new EmailNotification(message);
case 'sms': return new SMSNotification(message);
default: throw new Error(`Unknown type: ${type}`);
}
}
}
Фабрика с реестром (предпочтительнее switch)
class ShapeFactory {
static registry = new Map();
static register(type, creator) { this.registry.set(type, creator); }
static create(type, ...args) {
const creator = this.registry.get(type);
if (!creator) throw new Error(`Type "${type}" not registered`);
return creator(...args);
}
}
ShapeFactory.register('circle', (r) => ({ type: 'circle', area: => Math.PI * r * r }));
ShapeFactory.register('rect', (w, h) => ({ type: 'rect', area: => w * h }));
// Можно добавлять новые типы без изменения фабрики (OCP)
ShapeFactory.register('triangle', (b, h) => ({ type: 'triangle', area: => 0.5 * b * h }));
API Response Parser
function createApiResponse({ status, data, error }) {
if (status >= 200 && status < 300) {
return {
ok: true, status, data,
getData { return this.data; }
};
}
return {
ok: false, status, error: error || 'Unknown',
getData { throw new Error(this.error); }
};
}
Где используется в JS-экосистеме
- Node.js:
Buffer.from,Array.from,Object.create— фабрики - DOM:
document.createElement(tag)— Factory Method - React: компоненты как фабрики React-элементов
- Знаковая
factorify— обобщённая фабрика из лекций автора
Подводные камни
- В JS объект-литерал в стрелке нужно оборачивать в `` — иначе будет блок кода.
- Фабрика теряет
instanceof-проверку — гибкость минус полиморфизм. - V8 группирует одноформенные объекты в hidden class — фабрика без класса не теряет производительности.
- Фабрика когда достаточно конструктора — избыточно:
createPoint(x, y) => new Point(x, y). - Огромный
switchнарушает OCP — используй реестр.
Главные тезисы автора
- В JS «часто объекты не из классов создают, а собираются из всякого трэша» — литералов, примесей, оберток.
factorify— обобщённая фабрика, которая превращает любой класс в фабрику.- Фабрика стоит выше класса в иерархии абстракций, но ниже пула.
🎓 Источники
- 🎓 Фабрики и пулы объектов в JavaScript, factorify, poolify · 2018-12-03 · 56 мин
- Лестница
instance → class → factory → pool - Скрытые классы V8 при фабриках
- factorify / poolify как обобщённые операторы
- Лестница
- 🎓 GoF Patterns Обзор всех паттернов · 2025-04-29
- Factory не из GoF, но в JS повсеместно
- Refactoring Guru — Factory Method
- Patterns.dev — Factory