Что такое паттерн проектирования Singleton (Одиночка)?

«Что такое паттерн проектирования Singleton (Одиночка)?» — вопрос из категории Паттерны, который задают на 23% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Классическая реализация (ленивая, с двойной проверкой блокировки):

public class Singleton {
    // volatile гарантирует видимость изменения instance всеми потоками
    private static volatile Singleton instance;

    // Приватный конструктор блокирует создание через new
    private Singleton() {
        // Инициализация
    }

    public static Singleton getInstance() {
        // Первая проверка (без блокировки для скорости)
        if (instance == null) {
            synchronized (Singleton.class) {
                // Вторая проверка внутри synchronized
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Альтернативные способы реализации:

  1. Eager Initialization (ранняя инициализация):
    public class Singleton {
        private static final Singleton INSTANCE = new Singleton();
        private Singleton() {}
        public static Singleton getInstance() { return INSTANCE; }
    }
  2. Static Holder (идиома Bill Pugh): (Рекомендуется)
    public class Singleton {
        private Singleton() {}
        private static class Holder {
            private static final Singleton INSTANCE = new Singleton();
        }
        public static Singleton getInstance() { return Holder.INSTANCE; }
    }

    Класс Holder загрузится только при первом вызове getInstance(), что обеспечивает ленивую инициализацию и потокобезопасность.

Области применения и недостатки:

Применение Недостатки
Логгеры, менеджеры конфигурации, кеши, пулы соединений с БД, фасады к аппаратному обеспечению. Тестирование: Глобальное состояние усложняет модульное тестирование.
Нарушение SRP: Класс управляет и своим жизненным циклом, и бизнес-логикой.
Потокобезопасность: Требует аккуратной реализации в многопоточной среде.