Lapa Knowledge Base
Порождающие паттерны

Singleton (Одиночка)

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

Проблема

Singleton решает две проблемы одновременно, нарушая принцип единственной ответственности:

  1. Гарантирует наличие единственного экземпляра класса — когда нужен строгий контроль над количеством экземпляров
  2. Предоставляет глобальную точку доступа — когда нужен глобальный доступ к экземпляру

Решение

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

Структура

Singleton
├── instance: Singleton
├── Singleton() // приватный конструктор
└── getInstance(): Singleton

Пример реализации

JavaScript (ES6+)

class DatabaseConnection {
    static instance = null;
    
    constructor() {
        if (DatabaseConnection.instance) {
            return DatabaseConnection.instance;
        }
        
        // Инициализация подключения к базе данных
        this.connectionString = 'mongodb://localhost:27017/mydb';
        this.isConnected = false;
        
        DatabaseConnection.instance = this;
    }
    
    static getInstance() {
        if (!DatabaseConnection.instance) {
            DatabaseConnection.instance = new DatabaseConnection();
        }
        return DatabaseConnection.instance;
    }
    
    connect() {
        if (!this.isConnected) {
            console.log('Подключение к базе данных...');
            this.isConnected = true;
        }
        return this;
    }
    
    disconnect() {
        this.isConnected = false;
        console.log('Отключение от базы данных');
    }
}

// Использование
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();

console.log(db1 === db2); // true - это один и тот же объект

TypeScript

JavaScript (ES6+)
class Logger {
    private static instance: Logger;
    private logs: string[] = [];
    
    private constructor() {}
    
    public static getInstance(): Logger {
        if (!Logger.instance) {
            Logger.instance = new Logger();
        }
        return Logger.instance;
    }
    
    public log(message: string): void {
        const timestamp = new Date().toISOString();
        this.logs.push(`[${timestamp}] ${message}`);
        console.log(`[${timestamp}] ${message}`);
    }
    
    public getLogs(): string[] {
        return [...this.logs];
    }
}

// Использование
const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();

logger1.log('Первое сообщение');
logger2.log('Второе сообщение');

console.log(logger1 === logger2); // true

Когда использовать

Используйте паттерн Singleton, когда:

  • В системе должен быть единственный экземпляр класса
  • Нужна глобальная точка доступа к этому экземпляру
  • Создание объекта дорого (например, подключение к базе данных)
  • Нужно контролировать доступ к общему ресурсу

Преимущества

  • Гарантирует единственный экземпляр класса
  • Предоставляет глобальную точку доступа
  • Ленивая инициализация (создание только при необходимости)
  • Контроль над жизненным циклом объекта

Недостатки

  • Нарушает принцип единственной ответственности
  • Скрывает зависимости в коде
  • Усложняет тестирование
  • Может стать антипаттерном при неправильном использовании
  • Проблемы с многопоточностью (если не реализован правильно)

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

  • Dependency Injection — передача зависимостей через конструктор
  • Service Locator — централизованный реестр сервисов
  • Factory Method — для создания объектов с контролем жизненного цикла

Антипаттерн?

Singleton часто считается антипаттерном, потому что:

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

Используйте Singleton осторожно и только когда действительно нужен единственный экземпляр объекта!


Помните: Singleton — это мощный паттерн, но используйте его разумно!

Copyright © 2026