Примеры использования Паттерн Singleton (Одиночка) - страница 2

Шрифт
Интервал

стр.

> printf("saveIni\n");

>}


>void Application::Run() {

> wnd=new Window();

> //цикл обработки сообщений

> delete wnd;

>}

>Application* Application::_self=NULL;

Модуль WINDOW

>#include "app.h"

>class Window {

> int width;

> int height;

>public:

> Window() {

>  Application *p=Application::Instance();

>  p->loadIniInt(string("Window"), string("width"));

>  p->loadIniInt(string("Window"), string("height"));

> }

> ~Window() {

>  Application *p=Application::Instance();

>  p->saveIniInt(string("Window"), string("width"), width);

>  p->saveIniInt(string("Window"),string("height"), height);

> }

>};


Этот листинг показывает, как можно организовать каркас оконного приложения, используя паттерн Singleton. Из класса окна требуется доступ к некоторым функциям объекта Application. Поскольку объект приложения существует всегда в одном экземпляре, то он реализует паттерн Singleton, а доступ к объекту приложения из объекта окна осуществляется благодаря методу Instance().

Проблема удаления объекта “Singleton”.

В приведенной выше реализации класса Singleton, есть метод создания объекта, но отсутствует метод его удаления. Это означает, что программист должен помнить в каком месте программы объект удаляется. Другая проблема, связанная с удалением объекта из памяти, возникает при полиморфном использовании объектов класса. Рассмотрим, например, такой код.

Листинг 5

>class Client {

> Singleton * _pS;

>public:

> SetObject(Singleton *p) {_pS=p;}

> ~Client(){delete _pS;}

>};


>void main() {

> Client c1,c2;

> c1.SetObject(Singleton::Instance());

> c2.SetObject(Singleton::Instance());

>}


Эта программа будет пытаться удалить дважды один и тот же объект, что приведет к исключительной ситуации в программе. При выходе из контекста функции main, сначала будет вызван деструктор объекта c2, который удалит объект класса Singleton, а затем то же самое попытается сделать и деструктор объекта c1. В связи с этим, хотелось бы иметь механизм, позволяющий автоматически отслеживать ссылки на объект класса Singleton, и автоматически удалять его только тогда, когда на объект нет активных ссылок. Для этого используют специальный метод FreeInst(), удаляющий объект только в случае, если активных ссылок на него нет.

Другая задача, которую надо решить – запрет удаления клиентом объекта Singleton посредством оператора delete. Это решается помещением деструктора в секцию protected.Тем самым, клиенту ничего не остается, как использовать пару Instance()/FreeInst() для управления временем жизни объекта.

Листинг 6

>class Singleton {

>protected:

> static Singleton* _self;

> static int _refcount;

> Singleton(){};

> ~Singleton(){};

>public:

> static Singleton* Instance();

void FreeInst() {_refcount--; if(!_refcount) {delete this; _self=NULL;}}

>};


В данном примере, в класс Singleton введен счетчик ссылок. Метод FreeInst() вызывает оператор удаления только тогда, когда _refcount равен нулю.

Проблема наследования

Если существует необходимость наследовать от класса Singleton, то следует придерживаться определенных правил.

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

Во-вторых, в базовом классе деструктор должен быть объявлен как виртуальный: в определенный момент клиент вызывает метод FreeInst для указателя на базовый класс. Поскольку метод FreeInst сводится к оператору delete this, то в случае, если деструктор не виртуальный, будет вызван деструктор базового класса, но не будет вызван деструктор класса-потомка. Чтобы избежать такой ситуации, следует явно объявить деструктор базового класса виртуальным.

В-третьих, конструктор класса-потомка также должен быть объявлен в защищенной секции, чтобы избежать возможности создания объекта класса напрямую, минуя метод Instance().

Листинг 7

>class Singleton {

>protected:

> static Singleton* _self;

> static int _refcount;

> Singleton(){}


стр.

Похожие книги