Паттерн Одиночка (Singleton) - описание (шаблон)

[Singleton]

Приведём описание паттерна по данным стандартным пунктам

Название и классификация

Одиночка - паттерн, относящийся к группе порождающих паттернов (шиблонов).

Назначение

Гарантирует, что у класса есть только один экземпляр (ещё точнее можно сказать, что у "класса данного типа может быть только один экземпляр"), и предоставляет к нему глобальную точку доступа.

Псевдоним

Английское название Singleton (одиночка) часто калькируется в русскоязычные тексты и паттерн Одиночка называют "Синглтоном". Мы же будем использовать русское название так как оно весьма удачно.

Мотивация

Для некоторых классов важно, чтобы существовал только один экземпляр.
Например:

  1. Хотя в системе может быть много принтеров, но возможен лишь один спулер.
  2. Должны быть только одна файловая система и единственный оконный менеджер.
  3. В цифровом фильтре может находиться только один аналого-цифровой преобразователь (АЦП). Бухгалтерская система обслуживает только одну компанию.

Как гарантировать, что у класса есть единственный экземпляр и что этот экземпляр легко доступен?
Глобальная переменная дает доступ к объекту, но не запрещает инстанцировать класс в нескольких экземплярах.
Более удачное решение достигается в том случае, если сам класс:

  1. контролирует то, что у него есть только один экземпляр
  2. может запретить создание дополнительных экземпляров, перехватывая запросы на создание новых объектов
  3. и он же способен предоставить доступ к своему экземпляру.

Это и есть назначение паттерна одиночка.

Применимость

Паттерн одиночка следует использовать, когда:

  1. должен быть ровно один экземпляр некоторого класса, легко доступный всем клиентам;
  2. единственный экземпляр должен расширяться путем порождения подклассов, и клиентам нужно иметь возможность работать с расширенным экземпляром без модификации своего кода.

Структура

Фактически сам паттерн описывает единственный класс:
паттерн синглтон одиночка - структура

Участники

Так как класс единственный - то и участник один - он сам:
Singleton (одиночка) обладает следующими свойствами:

  1. определяет операцию Instance, которая позволяет клиентам получать доступ к единственному экземпляру.Instance D это операция класса, то есть метод класса в терминологии Smalltalk или статическая функция-член в C++ (функция должна быть стаитческой для того чтобы к ней был доступ тогда когда объект ещё не создан);
  2. может нести ответственность за создание собственного уникального экземпляра.

Отношения

Клиенты получают доступ к экземпляру класса Singleton только через его операцию Instance

Результаты

У паттерна одиночка есть определенные достоинства:

  1. контролируемый доступ к единственному экземпляру
  2. уменьшение числа имён
  3. допускает уточнение операций и представления
  4. допускает переменное число экземпляров
  5. большая гибкость, чем у операций класса

1) Контролируемый доступ к единственному экземпляру.
Поскольку класс Singleton инкапсулирует свой единственный экземпляр, он полностью контролирует то, как и когда клиенты получают доступ к нему;

2) Уменьшение числа имен.
Паттерн одиночка - шаг вперед по сравнению с глобальными переменными. Он позволяет избежать засорения пространства
имен глобальными переменными, в которых хранятся уникальные экземпляры;

3) Допускает уточнение операций и представления.

От класса Singleton можно порождать подклассы, а приложение легко сконфигурировать экземпляром расширенного класса. Можно конкретизировать приложение экземпляром того класса, который необходим во время выполнения;

4) Допускает переменное число экземпляров.
Паттерн позволяет вам легко изменить свое решение и разрешить появление более одного экземпляра класса Singleton. Вы можете применять один и тот же подход для управления числом экземпляров, используемых в приложении. Изменить нужно будет лишь операцию, дающую доступ к экземпляру класса Singleton;

5) Большая гибкость, чем у операций класса.

Еще один способ реализовать функциональность одиночки - использовать операции класса, то есть статические функции-члены в C++ и методы класса в Smalltalk. Но оба этих приема препятствуют изменению дизайна, если потребуется разрешить наличие нескольких экземпляров класса. Кроме того, статические функции-члены в C++ не могут быть виртуальными, так что их нельзя полиморфно заместить в подклассах.

Реализация

При использовании паттерна одиночка надо рассмотреть следующие вопросы:
гарантирование единственного экземпляра

1) Гарантирование единственного экземпляра.

Паттерн одиночка устроен так, что тот единственный экземпляр, который имеется у класса, самый обычный, но больше одного экземпляра создать не удастся. Чаще всего для этого прячут операцию, создающую экземпляры, за операцией класса
(то есть за статической функцией-членом или методом класса), которая гарантирует создание не более одного экземпляра.

Данная операция имеет доступ к переменной, где хранится уникальный экземпляр, и гарантирует инициализацию переменной этим экземпляром перед возвратом ее клиенту. При таком подходе можно не сомневаться, что одиночка будет создан и инициализирован перед первым использованием.
В C++ операция класса определяется с помощью статической функции-члена Instance класса Singleton. В этом классе есть также статическая переменная (член instance, которая содержит указатель на уникальный экземпляр).

Класс Singleton объявлен следующим образом:

class Singleton{
// то, что мы будем использовать вместо конструктора
// это единственная точка входа как для создания
// так и для получения уже имеющейся сущности
public:
   static Singleton * Instance();

protected: // прячем стандартный конструкутор
   Singleton();

private:
   static Singleton* _instance; // здесь будет хранится уникальный экземпляр
};

А реализуется класс так(в C++ можно отдельно класс объявить и отдельно прописать реализацию):

Singleton*Singleton::_instance = 0;

Singleton*Singleton::Instance() { // проверяем - создана ли уже данная сущность
  if (_instance == 0) { // проверка существования
// если нет, то создаём новую
    _instance= new  Singleton;
 }
 return _instance; // возвращаем объект-одиночку
}

Проверку существования можно сделать иной (именно она опередляет "модификацию" одиночки) - например включить (реализовать) поиск по реестру - чтобы можно было
создавать целый каталог одиночек - где каждый будет в единственном экземпляре.

Подобного можно добивиться, например, передавая в Instance() некоторое имя (строку) - которое должно быть уникальным в случае если мы хотим создать новый экземпляр.

Пример кода

Рассмотрим пример реализации паттерна Одиночка на PHP.

Известные применения

Применяется во многих системах, моделирующих реальные объекты.

Родственные паттерны

С помощью паттерна одиночка могут быть реализованы многие паттерны.
Смотри описание:

  1. абстрактной фабрики
  2. строителя
  3. прототипа