Что такое синглтон

Одиночка (шаблон проектирования)

C++, Singleton, Одиночка, Паттерны, Синглтон

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

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

Пример реализация паттерна Singleton на C++

Технически реализовать объект-Синглтон и использовать его в приложении довольно просто (что подкупает):

При желании объект-Синглтон можно адаптировать к многопоточной среде выполнения с помощью мьютексов.

Всегда думайте перед созданием Синглтона

Заманчиво иметь некий объект, доступный в любой точке программы. Но это нарушает многие принципы создания хорошего кода. Поэтому не спешите добавлять Синглтоны, которые усложняют логику программы и вносят лишние зависимости.

Рассмотрим пример. Может показаться хорошей идеей создать класс для управления настройками приложения в виде Синглтона. Тогда все компоненты приложения смогут видеть необходимые опции и легко их использовать. С одной стороны, идея кажется довольно неплохой. Конфигурация приложения действительно может быть представлена уникальной сущностью. А свободный доступ к Синглтону упростит использование конфигурации.

Однако в этом случае появляется серьезная проблема. Все компоненты начинают зависеть от Синглтона. Если понадобится перенести только один из классов в другое приложение, то придется тащить вместе с ним и Синглтон, который может быть предназначен для управления параметрами десятков других классов. Лучше потратить немного больше времени на проектирование, но обеспечить четкую передачу параметров в классы через их конструкторы, а не через незаметный Синглтон.

К тому же, паттерн Синглтон усложняет использование полиморфизма и других прелестей ООП, которые могут понадобится, когда уже минимальным рефакторингом обойтись не удастся.

Хотя есть и вполне безобидные применения Синглтонов. Например, при реализации другого паттерна: Абстрактная Фабрика.

Также использование Синглтона оправдано для представления физически уникальных ресурсов компьютера. Например, систему слежения за подключением/отключением USB-устройств уместно реализовать в виде Синглтона.

Понравилась статья?
Не забудь поделиться ей с друзьями!

Похожие публикации

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

Преимущества синглтонов перед глобальными переменными:

1) Синглтон гарантирует, что будет создан только один экземпляр класса.

Например, классы Log, Renderer, FileManager (обычно любой менеджер в системе по сути синглтон) и т.п. могут существовать только в единственном экземпляре . Глобальная переменная не удовлетворяет этому требованию, так как раз мы можем создать один экземпляр класса, значит мы можем «наплодить» хоть сколько таких же экземпляров, что в большинстве случаев приведёт к краху программы. При использовании синглтона, мы просто делаем конструктор класса private и объявляем синглтон-контейнер другом этого класса.

2) При использовании синглтонов почти не нужно заботиться о порядке создания глобальных объектов.

Например, класс Renderer при конструировании использует класс Log, который в свою очередь при конструировании использует класс FileManager.

В 99% случаев если классы созданы не в том порядке (надо FileManager, Log и последним Renderer), программа упадёт ещё до входа в функцию main(). При использовании глобальных переменных, приходится вникать в код каждого из «глобальных» классов, чтобы понять как они взаимосвязаны и инициализировать их в правильном порядке. Причем, если глобальные переменные находятся в разных модулях программы, то порядок их создания не специфицирован! Эта проблема с лёгкостью решается при помощи синглтонов: объект в них конструируется только при первом обращении к нему. Проблемы могут возникнуть только если конструкторы нескольких классов «зациклены» друг на друга, но это всего лишь свидетельствует о «криворукости» программиста.

Но и тут синглтоны дают приличное преимущество. Допустим, есть два класса, А и В, объекты которых должны быть глобальными. Класс А при создании использует какие-либо методы класса В. Это означает, что мы либо должны гарантировать, что объект класса В будет создан до А, либо В будет создаваться в конструкторе А. А если класс В также использует класс А? Если еще немного усложнить эту систему, то реализация без синглтонов будет довольно кривой.

Что такое синглтон в С#?

Это еще без учета того, что в разных приложениях (собственно движок, плагины, утилиты итд) нужны разные классы, и для каждого приложения необходимо следить за правильным порядком создания. Синглтоны как раз и призваны снизить извращения подобного рода до минимума.

3) Не нужно заботиться об удалении глобальных объектов.

А что если при уничтожении, Renderer захочет сообщить что-либо архиважное классу Log, а того уже и нет в помине? Правильно, получится геморрой. Иногда надо, чтобы некоторые уничтоженные объекты снова «оживали» при надобности. С помощью обычных глобальных переменных эта проблема не решаема. У синглтонов и с этим всё в порядке: достаточно лишь «сказать» контейнеру, что если объект уже уничтожен, а к нему кто-то обращается, его нужно восстановить.

О синглтонах можно прочитать в книге Андрея Александреску «Современное проектирование на C++». В этой же книге приведён пример реализации класса SingletonHolder для библиотеки Loki (http://sourceforge.net/projects/loki-lib/). Эта реализация основана на стратегиях Strategy, всего их три:

1) Стратегия Creation — задаёт способ создания объекта при первом обращении к нему. Три предложенных варианта реализации:
CreateUsingNew (задан по умолчанию) — создаёт объект с помощью оператора new и конструктора по умолчанию.
CreateUsingMalloc — создаёт объект с помощью функции std::malloc и конструктора по умолчанию.
CreateStatic — создаёт объект в статической памяти.

2) Стратегия LifeTime — задаёт время жизни и уничтожения объекта. Четыре предложенных реализации:
DefaultLifeTime (задан по умолчанию) — объект удаляется в соответствии со стандартными правилами C++.
PhoenixSingleton — то же самое, что и DefaultLifeTime, но при попытке обращения к уничтоженному объекту, он создаётся снова.
SingletonWithLongevity — предполагает пользовательскую функцию, которая возвращает относительное время жизни объекта.
NoDestroy — объект не уничтожается средствами программы. Занимаемую им память «подчищает» операционная система после завершения работы программы.

3) Стратегия ThreadingModel — задаёт поведение внутреннего указателя на хранимый объект. Две реализации:
SingleThreaded (задан по умолчанию) — для использования в одном потоке.
ClassLevelLockable — для ипользования из нескольких потоков.
Кроме всех перечисленных реализаций, вы можете написать свою специфическую реализацию конкретной стратегии.

Пример использования:

#include<loki/singleton.h>class CLog; typedef Loki::SingletonHolder<CLog, Loki::CreateStatic, Loki::PhoenixSingleton> Log; class CLog { friendstruct Loki::CreateStatic<CLog>; public: void OutText(const std::string &txt) {…}; private: //Защищаем наш класс CLog(); CLog(const CLog &x); const CLog &operator=(const CLog &x); CLog *operator&()const; ~CLog(); }; //Использованиеvoid MegaFunction() { Log::Instance().OutText("Халлоу, чуваки!"); }

Ссылки:

Для расширенной информации о синглтонах читайте:
boost::singleton_ptr (код, из boost vault)
Singleton Pattern (англ)
Singletons Are Good (англ, коротко)
Singletons Are Evil (англ, длинно)
Singleton Considered Misleadingly Named (англ)
Почему синглетоны — отстой? (внимание: ненормативная лексика!)

Что такое Синглтон (Singleton)?

17 декабря 2005

#паттерны, #шаблоны проектирования

Обновление: 23 апреля 2010

Шаблон проектирования Singleton (Одиночка)

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

Одиночка — паттерн, порождающий объекты

Назначение

Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему

глобальную точку доступа.

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

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

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

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

Структура__

Участники

Singleton — одиночка:

— определяет операцию Instance, которая позволяет клиентам получать доступ к единственному экземпляру. Instance — это операция класса, и статическая функция-член

в C++;

— может нести ответственность за создание собственного уникального экземпляра.

Отношения

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

Результаты

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

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

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

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

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

Реализация

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

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

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

class Singleton {

public: static Singleton* Instance();

protected: Singleton();

private: static Singleton* instance;

};

А реализация такова:

Singleton* Singleton::_instance = 0;

Singleton* Singleton::Instance () {

if (_instance == 0) {_instance = new Singleton;}

return instance;

}

Клиенты осуществляют доступ к одиночке исключительно через функцию-член Instance. Переменная instance инициализируется нулем, а статическая функция-член Instance возвращает ее значение, инициализируя ее уникальным экземпляром, если в текущий момент оно равно 0. Функция Instance использует отложенную инициализацию: возвращаемое ей значение не создается и не хранится вплоть до момента первого обращения.

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

При проектировании приложения стоит учесть и минимизировать возможные негативные последствия использования Одиночки. Они являются проявлением его «глобализации». В частности:

  1. Многие части приложения становятся зависимы от него и, косвенно, друг от друга.

    Паттерн Singleton. Описание. Пример использования

    Это усложняет внесение изменений в дальнейшем.

  2. Приложение становится сложнее тестировать, т.к. данные, полученные от Одиночки, могут быть созданы в другом модуле.

Альтернативой Одиночке является статический класс, который имеет следующие ограничения:

  • он не может быть наследником других классов и реализовывать интерфейсы;

  • нельзя создать экземпляр статического класса. Следовательно, его невозможно использовать в качестве параметра или возвращаемого значения.

Добавить комментарий

Закрыть меню