Паттерны проектирования — это как рецепты в кулинарной книге. Вы не обязаны следовать им дословно, но они экономят время и спасают от типичных ошибок. В этой статье разберём, какие паттерны стоит использовать в JavaScript-проектах, а какие — обходить стороной.
Что такое паттерн проектирования и зачем он нужен
Паттерн — это проверенное решение типовой задачи. Вы не изобретаете велосипед, а берёте готовую конструкцию, которую уже обкатали тысячи разработчиков. В JavaScript паттерны особенно полезны, потому что язык гибкий: можно писать и процедурно, и объектно, и функционально. Без структуры легко превратить проект в спагетти.
Основные плюсы:
- Код становится понятнее для других (и для вас через полгода).
- Меньше дублирования и больше переиспользования.
- Проще тестировать и расширять.
Но есть и минус: не тащите паттерны туда, где они не нужны. Иногда простая функция лучше навороченного фабричного метода.
Популярные паттерны в JavaScript: от простого к сложному
Начнём с самых ходовых. Их вы встретите в любом крупном проекте.
Модуль (Module)
Самый распространённый паттерн в JS. Он позволяет инкапсулировать код и не засорять глобальную область. Раньше использовали IIFE, сейчас — ES-модули.
// ES-модуль: файл math.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// Использование в другом файле
import { add, multiply } from './math.js';
console.log(add(2, 3)); // 5
Просто, эффективно, поддерживается всеми современными сборщиками.
Фабрика (Factory)
Когда нужно создавать объекты, но вы не хотите светить классы и логику создания — используйте фабрику. Она возвращает готовый объект, скрывая детали.
function createUser(type) {
const roles = {
admin: { canEdit: true, canDelete: true },
user: { canEdit: false, canDelete: false }
};
return {
type,
...roles[type],
greet() {
console.log(`Привет, я ${this.type}`);
}
};
}
const admin = createUser('admin');
admin.greet(); // Привет, я admin
console.log(admin.canEdit); // true
Фабрика хороша, когда создание объекта — это не просто вызов конструктора, а целый процесс.
Наблюдатель (Observer)
Классика для работы с событиями. Один объект (издатель) уведомляет других (подписчиков) об изменениях. В JS это встроено в DOM-события, но можно реализовать и вручную.
class EventEmitter {
constructor() {
this.listeners = {};
}
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
}
emit(event, data) {
if (this.listeners[event]) {
this.listeners[event].forEach(cb => cb(data));
}
}
}
const emitter = new EventEmitter();
emitter.on('message', (text) => console.log(`Получено: ${text}`));
emitter.emit('message', 'Привет, мир!'); // Получено: Привет, мир!
Такой паттерн часто используют в React-компонентах или в Node.js для работы с потоками.
Стратегия (Strategy)
Позволяет менять алгоритм на лету. Вместо кучи if-else вы выносите каждую логику в отдельную функцию и выбираете нужную.
const strategies = {
card: (amount) => `Оплата картой на ${amount} руб.`,
cash: (amount) => `Оплата наличными: ${amount} руб.`,
crypto: (amount) => `Оплата криптой: ${amount} руб.`
};
function pay(method, amount) {
if (!strategies[method]) {
throw new Error('Неизвестный метод оплаты');
}
return strategies[method](amount);
}
console.log(pay('card', 1000)); // Оплата картой на 1000 руб.
console.log(pay('crypto', 500)); // Оплата криптой: 500 руб.
Код становится чище, а добавление нового способа оплаты занимает одну строчку.
Когда паттерны вредны: антипаттерны
Некоторые паттерны в JavaScript устарели или изначально были плохими. Например, Singleton (Одиночка) часто критикуют за глобальное состояние и сложности с тестированием. В JS его можно заменить на модуль с единственным экземпляром, но лучше избегать, если нет реальной необходимости.
Ещё один пример — глубокая вложенность (callback hell). Это не совсем паттерн, но антипример. Решается промисами или async/await.
Сравнение паттернов: что и когда использовать
Чтобы не запутаться, вот таблица с краткими рекомендациями.
| Паттерн | Когда использовать | Пример из жизни |
|---|---|---|
| Модуль | Всегда, для организации кода | Любой файл с экспортами |
| Фабрика | Создание объектов со сложной логикой | Генерация пользователей по ролям |
| Наблюдатель | Событийная модель, реактивность | Клик по кнопке, обновление UI |
| Стратегия | Выбор алгоритма во время выполнения | Способы оплаты, сортировки |
Не обязательно пихать все паттерны в один проект. Выбирайте под задачу.
Практические советы по внедрению
- Начинайте с малого: добавьте один паттерн там, где код уже начал путаться.
- Обсуждайте с командой: паттерн должен быть понятен всем, иначе он станет обузой.
- Изучайте исходники библиотек: в React, Vue, Lodash паттерны используются повсеместно.
- Не бойтесь рефакторить: если паттерн не прижился — перепишите.
Что в итоге
Паттерны проектирования в JavaScript — это не догма, а набор проверенных приёмов. Они помогают писать чистый, расширяемый код, но только если применять их с умом. Начните с модулей и фабрик, добавьте наблюдателя для событий, а стратегию — для гибких алгоритмов. И помните: главное — чтобы код был понятен вам и вашей команде.
Экспериментируйте, ошибайтесь, рефакторьте. Со временем вы начнёте чувствовать, где какой паттерн уместен.



