Что такое паттерн Singleton и как его реализовать?

«Что такое паттерн Singleton и как его реализовать?» — вопрос из категории Основы программирования, который задают на 10% собеседований QA Тестировщик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Основные сценарии использования:

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

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

Потокобезопасная реализация на Java (с отложенной инициализацией):

public class DatabaseConnectionPool {
    // Приватное статическое поле для хранения единственного экземпляра
    private static volatile DatabaseConnectionPool instance;

    // Приватный конструктор блокирует создание через new
    private DatabaseConnectionPool() {
        // Инициализация пула соединений
        System.out.println("DatabaseConnectionPool instance created.");
    }

    // Публичный статический метод для глобального доступа
    public static DatabaseConnectionPool getInstance() {
        // Проверка без блокировки для производительности (Double-Checked Locking)
        if (instance == null) {
            // Синхронизация только на этапе первого создания
            synchronized (DatabaseConnectionPool.class) {
                if (instance == null) {
                    instance = new DatabaseConnectionPool();
                }
            }
        }
        return instance;
    }

    // Пример метода бизнес-логики
    public Connection getConnection() {
        // Логика выдачи соединения из пула
        return null; // Заглушка
    }
}

// Использование
public class Main {
    public static void main(String[] args) {
        // Все вызовы возвращают один и тот же объект
        DatabaseConnectionPool pool1 = DatabaseConnectionPool.getInstance();
        DatabaseConnectionPool pool2 = DatabaseConnectionPool.getInstance();

        System.out.println(pool1 == pool2); // Выведет: true
        Connection conn = pool1.getConnection();
    }
}

Ключевые элементы реализации:

  1. Приватный конструктор.
  2. Приватное статическое поле для хранения экземпляра.
  3. Публичный статический метод getInstance() для доступа.
  4. Потокобезопасность (важно в многопоточных средах, как в примере выше).

Альтернатива в Python (используя модуль): В Python сам модуль является естественным синглтоном. При необходимости можно использовать декоратор или метакласс.