PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Паттерны проектирования в JavaScript: Singleton, Factory, Observer

    Паттерны проектирования в JavaScript: Singleton, Factory, Observer

    Аватар автора Паттерны проектирования в JavaScript: Singleton, Factory, Observer

    Антон Ларичев

    Иконка календаря24 мая 2026
    JavaScriptПаттерны проектированияАрхитектураmiddleИконка уровня middle
    Картинка поста Паттерны проектирования в JavaScript: Singleton, Factory, Observer

    Введение

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

    В этой статье разберём три фундаментальных паттерна: Singleton, Factory и Observer. Каждый из них решает свою задачу и применяется в реальных проектах — от конфигурационных модулей до систем событий и фреймворков.

    Singleton

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

    class Logger {
      constructor() {
        // Если экземпляр уже создан, возвращаем его
        if (Logger.instance) {
          return Logger.instance;
        }
        this.logs = [];
        Logger.instance = this;
      }
    
      log(message) {
        const timestamp = new Date().toISOString();
        this.logs.push(`[${timestamp}] ${message}`);
        console.log(message);
      }
    
      getLogs() {
        return this.logs;
      }
    }
    
    const logger1 = new Logger();
    const logger2 = new Logger();
    
    console.log(logger1 === logger2); // true — это один и тот же объект
    

    В современном JavaScript Singleton часто реализуют через модули. ES-модули кешируются по умолчанию, поэтому экспортируемый объект автоматически становится синглтоном:

    // config.js
    const config = {
      apiUrl: process.env.API_URL,
      timeout: 5000
    };
    
    export default config;
    

    Любой импорт этого модуля получит один и тот же объект — без классов и проверок.

    Factory

    Factory (фабрика) инкапсулирует логику создания объектов. Вместо того чтобы напрямую вызывать new в коде клиента, мы передаём ответственность за создание специальной функции или классу. Это удобно, когда тип создаваемого объекта зависит от входных данных.

    class EmailNotification {
      send(message) {
        console.log(`Email: ${message}`);
      }
    }
    
    class SmsNotification {
      send(message) {
        console.log(`SMS: ${message}`);
      }
    }
    
    class PushNotification {
      send(message) {
        console.log(`Push: ${message}`);
      }
    }
    
    // Фабрика решает, какой класс инстанциировать
    function createNotification(type) {
      switch (type) {
        case 'email':
          return new EmailNotification();
        case 'sms':
          return new SmsNotification();
        case 'push':
          return new PushNotification();
        default:
          throw new Error(`Неизвестный тип уведомления: ${type}`);
      }
    }
    
    const notifier = createNotification('email');
    notifier.send('Заказ оформлен');
    

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

    Когда применять Factory

    Фабрика оправдана, если логика создания нетривиальна: нужно подобрать класс по условию, прочитать конфигурацию, провалидировать аргументы или поднять сложный объект с зависимостями. Если же конструктор простой — просто используйте new.

    Observer

    Observer описывает зависимость «один ко многим»: один объект (Subject) хранит список подписчиков (Observers) и уведомляет их об изменениях. Это основа любой событийной системы — от DOM-событий до Redux и RxJS.

    class EventEmitter {
      constructor() {
        this.listeners = new Map();
      }
    
      on(event, callback) {
        if (!this.listeners.has(event)) {
          this.listeners.set(event, []);
        }
        this.listeners.get(event).push(callback);
      }
    
      off(event, callback) {
        const callbacks = this.listeners.get(event);
        if (!callbacks) return;
        // Удаляем конкретный обработчик, чтобы избежать утечек памяти
        this.listeners.set(event, callbacks.filter(cb => cb !== callback));
      }
    
      emit(event, data) {
        const callbacks = this.listeners.get(event);
        if (!callbacks) return;
        callbacks.forEach(cb => cb(data));
      }
    }
    
    const orders = new EventEmitter();
    
    function sendEmail(order) {
      console.log(`Письмо для заказа ${order.id}`);
    }
    
    orders.on('created', sendEmail);
    orders.emit('created', { id: 42 });
    orders.off('created', sendEmail);
    

    Observer развязывает компоненты: издатель не знает, кто и как обрабатывает событие. Это упрощает тестирование и позволяет добавлять новых подписчиков, не меняя источник.

    Частые ошибки

    Singleton превращается в глобальную переменную. Чрезмерное использование синглтонов скрывает зависимости и усложняет тестирование. Если класс берёт данные из глобального синглтона, замокать их в юнит-тесте становится мучительно. Передавайте зависимости явно через конструктор там, где это возможно.

    Фабрика без выгоды. Если у вас один класс и одна ветка switch, фабрика не нужна — она лишь добавит уровень абстракции. Применяйте паттерн, когда вариантов создания действительно несколько и они меняются.

    Утечки в Observer. Забытые подписчики удерживают ссылки на объекты и мешают сборщику мусора их освободить. Всегда отписывайтесь, когда обработчик больше не нужен — особенно в SPA при размонтировании компонентов.

    Синхронные обработчики, которые блокируют издателя. Если один подписчик кидает исключение или зависает, остальные могут не получить событие. Оборачивайте вызовы в try/catch или используйте асинхронную доставку через queueMicrotask.

    Заключение

    Singleton, Factory и Observer — три базовых паттерна, которые встречаются почти в любом нетривиальном JavaScript-проекте. Singleton даёт единую точку доступа к разделяемому ресурсу, Factory скрывает сложность создания объектов, Observer связывает компоненты через события без жёстких зависимостей.

    Главное правило — не применять паттерны ради паттернов. Каждый из них решает конкретную проблему, и если проблемы нет, дополнительная абстракция только усложнит код. Начните с простого решения и вводите паттерн, когда почувствуете боль, которую он лечит.

    Иконка глаза303

    Комментарии

    0

    Постройте личный план изучения React state менеджер Zustand до уровня Middle — бесплатно!

    React state менеджер Zustand — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Next.js - с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Feature-Sliced Design

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.5
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста SOLID принципы в JavaScript: разбор на примерах
    Иконка аватараАнтон
    Иконка календаря26 июня 2026
    JavaScriptSOLIDООП+ 3middleИконка уровня middle

    SOLID принципы в JavaScript: разбор на примерах

    SOLID принципы в JavaScript — разбираем каждый принцип на реальных примерах кода, чтобы писать чистую и расширяемую архитектуру.

    Иконка чипа0
    Иконка глаза126
    Иконка комментариев0
    Картинка поста Замыкания в JavaScript: полное руководство с примерами
    Иконка аватараАнтон
    Иконка календаря25 июня 2026
    JavaScriptзамыканияосновы JS+ 2juniorИконка уровня junior

    Замыкания в JavaScript: полное руководство с примерами

    Замыкания в JavaScript — разбираем простыми словами: что захватывает функция, как работает scope chain и где применять на практике.

    Иконка чипа0
    Иконка глаза138
    Иконка комментариев0
    Картинка поста Event Sourcing на NestJS: реализация с нуля до продакшена
    Иконка аватараАнтон
    Иконка календаря19 июня 2026
    NestJSEvent SourcingCQRS+ 2seniorИконка уровня senior

    Event Sourcing на NestJS: реализация с нуля до продакшена

    Event Sourcing на NestJS: разбираем агрегаты, event store, проекции и снапшоты. Практический пример с кодом и типичные ошибки реализации.

    Иконка чипа0
    Иконка глаза188
    Иконка комментариев0
    Иконка чипа0