патерн singleton

[English version of the article can be found here].

Цим постом я відкриваю цикл статей, присвячених паттернам проектування. Все написане мною грунтується виключно на особистому досвіді.

Патерни проектування - це опис деяких проблем, що виникають під час об'єктно-орієнтованого проектування, а також способів їх вирішення (як практичних, так і теоретичних). Іншими словами - це приклади правильних підходів до вирішення типових задач проектування.

Проста реалізація Singleton

Один з найпростіших способів реалізувати патерн Singleton на мові Java виглядає так:

Тепер приведу деякі пояснення з приводу реалізації шаблону.

Метод getInstance () створить рівно один екземпляр класу Singleton. Цей метод оголошений як synchronized. Зроблено це ось чому. В багатопоточних програмах при одночасному виклику методу getInstance () з декількох потоків можна створити кілька примірників класу Singleton. А повинен залишитися тільки один!

Від модифікатора synchronized можна позбутися. Для цього _instance потрібно проинициализировать:

а в методі getInstance () прибрати конструкцію "if". Тоді ініціалізація відбудеться під час завантаження класу.

Але використання пізньої ініціалізації (lazy initialization) краще в разі, якщо створення екземпляра класу займає багато часу. Та й у разі ледачою ініціалізації є можливість обробити виникли ісключітальние ситуації при виклику конструктора.

Сінглтон з double-checked locking

Проблема з lazy инициализацией залишається тільки в тому, що синхронізація потрібна по ідеї тільки один раз, щоб кілька потоків не увійшли в критичну секцію одночасно. Але після створення екземпляра класу від синхронізації хотілося б позбутися.

Найпоширеніший спосіб позбутися від зайвої синхронізації - це double-checked locking, який виглядає таким чином:

Сінглтон з Instance Holder

А ось ще один вартий уваги варіант реалізації шаблону Одинак ​​з ледачою инициализацией:

Об'єкт буде ініціалізованим першим під час першого виклику методу getInstance (). Тобто ми перенесли проблему із синхронізацією на рівень завантажувача класів (class loader).

Але що якщо в додатку кілька Class Loader'ов або взагалі у нас розподілена система з декількома віртуальнмі машинами Java? Тоді все складно. Поговоримо про це іншим разом.

А взагалі зараз модно говорити, що реально крутий варіант патерну Одинак ​​виглядає так:

Ось власне і все. Ах да! Навіщо нам це потрібно.

Практичний приклад Сінглтона

Мені доводиться найчастіше використовувати цей патерн при роботі з конфігурацією. Іноді конфігурацію програми зручно зберігати в файлі. Припустимо, це буде простий текстовий файл "props.txt" з рядками типу "ключ = значення". Нам потрібно гарантувати, що конфігурація в програмі буде в єдиному екземплярі. Другу ми б і так не створили, але потрібно заборонити це робити користувачеві класу. Отже,

Тепер для роботи з конфігурацією можна використовувати конструкцію виду:

Якщо імена властивостей в "props.txt" мінятися не будуть, можна описати їх в класі таким чином:

а значення отримувати так:

Патерн Singleton корисний не тільки при роботі з конфігураціями. Його можна використовувати також при написанні ConnectionPool, Factory і інших речей.

Ось тепер точно все.

Схожі статті