Классический синглетон — класс-одиночка — представляет собой класс, объект которого может быть создан один единственный раз за весь период выполнения программы, и который существует в течение всего времени выполнения программы. Реализовать его можно разными способами, о которых можно прочитать в литературных трудах Банды Четырех и ставшего притчей во языцех Коплиена.
Однако, наиболее компактным, и не вызывающим головной боли при эксплуатации, является приведенный ниже вариант.
Читать дальше... //------------------------------------------------------------ class Service { private: Service() {} Service(const Service &) {} Service &operator=(const Service &) {} public: virtual ~Service() {} void Method1() {} void Method2() {} void Method3() {} static Service g_Instance; }; Service Service::g_Instance; //------------------------------------------------------------ // ниже приведен пример использования void Func1() { Service::g_Instance.Method1(); } void Func2() { Service::g_Instance.Method2(); } int main() { // раскомментируйте приведенные ниже строки // и убедитесь, что они не работают // Service local_Service; // Service another_local_Service(Service::g_Instance); // Service *ptr; *ptr=Service::g_Instance; Func1(); Func2(); Service::g_Instance.Method3(); return 0; } //------------------------------------------------------------
|
Предположим, экземпляр класса Service должен быть создан только один единственный раз. Для этого конструкторы делаются защищенными, защищенным делается так же оператор присваивания, а в открытом интерфейсе создается статическая переменная g_Instance (хотя и вопреки общепринятому обычаю включать в открытый интерфейс только методы, но не переменные, чтобы защитить их от несанкционированной модификации), являющаяся экземпляром самого класса. Очевидно, что g_Instance — это единственный случай, когда может быть вызван защищенный конструктор. Так же очевидно, что g_Instance не может быть модифицирована или перезаписана каким-то другим экземпляром класса Service, так как клиент класса лишен возможности самстоятельно вызвать конструктор.
Другим подходом к созданию синглетона является использование шаблона.
Читать дальше... //------------------------------------------------------------ template <class T> class SingletonKit { protected: SingletonKit() {} SingletonKit(const SingletonKit &); SingletonKit &operator= (const SingletonKit &); public: ~SingletonKit() {} static T g_Instance; }; template<class T> T SingletonKit<T>::g_Instance; //------------------------------------------------------------
|
Любой класс можно превратить в синглетон, используя SingletonKit, если соблюдать некоторые правила при написании класса, а именно:
— создать закрытый конструктор, запретить конструктор копирования и присваивание;
— сделать дружественным класс SingletonKit.
Далее приводится пример тестового класса.
//------------------------------------------------------------ class Test { friend class SingletonKit<Test>; // SingletonKit объявлен дружественным private: Test() { m_Data=-1; } Test(const Test &); // запрет копирования Test &operator= (const Test &); // и присваивания int m_Data; public: ~Test() {} void SetData(int Data) { m_Data=Data; } int GetData() { return m_Data; } }; //------------------------------------------------------------
|
Теперь объект класса Test можно использовать как синглетон. Единственный объект доступен через SingletonKit<Test>::g_Instance.
//------------------------------------------------------------ int main() { SingletonKit<Test>::g_Instance.SetData(100); Test &Ref=SingletonKit<Test>::g_Instance; int Data=Ref.GetData(); return 0; } //------------------------------------------------------------
|
Применение конструкции с шаблонным классом позволяет "осинглетить" любой класс в уже существующей иерархии классов. Например, если есть иерархия классов Window — DialogWindow — StatusWindow, где последний класс написан разработчиком и должен управлять выводом статуса программы, то вполне можно сделать его синглетным, если требуется. Для этого нужно лишь удовлетворить требованиям к объявлению класса.
//------------------------------------------------------------ class StatusWindow: public DialogWindow { friend class SingletonKit<StatusWindow>; // SingletonKit объявлен дружественным private: StatusWindow() {} StatusWindow(const StatusWindow &); // запрет копирования StatusWindow &operator= (const StatusWindow &); // и присваивания public: ~StatusWindow() {} }; //------------------------------------------------------------
|