← Назад к вопросам

Что такое паттерн Singleton?

1.3 Junior🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое паттерн Singleton

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

Основная идея

Паттерн Singleton особенно полезен в следующих случаях:

  • Централизованное управление ресурсами: логирование, конфигурация, пулы соединений
  • Предотвращение дублирования: база данных, кэш, состояние приложения
  • Синхронизация: единая точка для управления состоянием

Реализация в JavaScript

Классический подход с использованием класса

class Logger {
  constructor() {
    if (Logger.instance) {
      return Logger.instance;
    }
    this.logs = [];
    Logger.instance = this;
  }

  log(message) {
    this.logs.push(message);
    console.log(message);
  }

  getLogs() {
    return this.logs;
  }
}

const logger1 = new Logger();
const logger2 = new Logger();

console.log(logger1 === logger2); // true — один и тот же объект
logger1.log('Hello');
console.log(logger2.getLogs()); // ['Hello']

Статический метод getInstance()

Более явный и контролируемый подход:

class Database {
  constructor() {
    this.connection = null;
  }

  static getInstance() {
    if (!Database.instance) {
      Database.instance = new Database();
      Database.instance.connection = 'Connected to DB';
    }
    return Database.instance;
  }

  query(sql) {
    return `Executing: ${sql}`;
  }
}

const db1 = Database.getInstance();
const db2 = Database.getInstance();

console.log(db1 === db2); // true
console.log(db1.query('SELECT *')); // Executing: SELECT *

Объект-модуль (IIFE)

В JavaScript очень популярен подход с Immediately Invoked Function Expression:

const AppConfig = (() => {
  let instance;

  function createInstance() {
    return {
      apiUrl: 'https://api.example.com',
      timeout: 5000,
      debug: true,
      getApiUrl() {
        return this.apiUrl;
      }
    };
  }

  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

const config1 = AppConfig.getInstance();
const config2 = AppConfig.getInstance();

console.log(config1 === config2); // true
console.log(config1.getApiUrl()); // https://api.example.com

Практические примеры в современном фронтенде

Глобальный Store в React

// store.js
class AppStore {
  constructor() {
    this.state = {};
    this.listeners = [];
  }

  subscribe(callback) {
    this.listeners.push(callback);
  }

  setState(newState) {
    this.state = { ...this.state, ...newState };
    this.listeners.forEach(listener => listener(this.state));
  }

  static getInstance() {
    if (!AppStore.instance) {
      AppStore.instance = new AppStore();
    }
    return AppStore.instance;
  }
}

export default AppStore.getInstance();

Кэширование API запросов

class ApiCache {
  constructor() {
    this.cache = new Map();
  }

  set(key, value) {
    this.cache.set(key, value);
  }

  get(key) {
    return this.cache.get(key);
  }

  static getInstance() {
    if (!ApiCache.instance) {
      ApiCache.instance = new ApiCache();
    }
    return ApiCache.instance;
  }
}

const cache = ApiCache.getInstance();
cache.set('user:1', { id: 1, name: 'John' });
console.log(cache.get('user:1')); // { id: 1, name: 'John' }

Плюсы и минусы

Плюсы

  • Единственный экземпляр: гарантирует наличие только одного объекта
  • Глобальная точка доступа: удобство использования из любого места
  • Ленивая инициализация: объект создается при первом обращении
  • Безопасное управление ресурсами: контроль над инициализацией

Минусы

  • Скрытые зависимости: сложнее отследить, откуда берется объект
  • Сложность тестирования: нужно мокировать глобальное состояние
  • Нарушение SOLID: нарушает принцип единственной ответственности
  • Глобальное состояние: может привести к проблемам в многопоточности

Альтернативы

В современном JavaScript часто используют модули и зависимости вместо Singleton:

// Вместо Singleton — просто модуль
const userService = {
  getUser(id) {
    return fetch(`/api/users/${id}`).then(r => r.json());
  }
};

export default userService;

Итоги

  • Singleton гарантирует единственный экземпляр класса
  • В JavaScript реализуется через классы, методы или IIFE
  • Полезен для конфигурации, логирования, кэширования
  • Имеет как преимущества, так и недостатки
  • Современная альтернатива — ES6 модули и зависимости