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

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

стр.

virtual ~Singleton() {printf ("~Singleton\n");}

>public:

> static Singleton* Instance();

> void FreeInst();

>};


>class SinglImpl: public Singleton {

>protected:

SinglImpl(){}

>//объявление виртуальным в базовом классе автоматически

> //дает виртуальность в производном.

~SinglImpl() {printf ("~SinglImpl\n");}

>public:

> static Singleton* Instance() {

>  if(!_self) _self = new SinglImpl();

>  _refcount++;

>  return _self;

> }

>};


>void main() {

> Singleton *p = SinglImpl::Instance();

> …

> …

> …

> p->FreeInst();

>}


Результат работы:


~SinglImpl

~Singleton


Иногда может возникнуть ситуация, при которой клиент должен полиморфно работать с объектами, имеющими общий базовый класс, но некоторые из них реализуют паттерн Singleton, а некоторые нет. Проблема возникает в момент освобождения объектов, так как у простых классов нет механизма отслеживания ссылок, а у классов, реализующих Singleton, он есть. При вызове метода FreeInst() через указатель на базовый класс будет вызываться FreeInst() базового класса, не имеющего понятия о подсчете ссылок. Это приведет и к безусловному удалению объектов “Singleton” из памяти. Для предотвращения такого поведения следует объявить виртуальным метод FreeInst() в базовом классе и реализовать специфическое поведение метода для классов Singleton. Реализация FreeInst() в базовом классе предоставляет механизм удаления объектов, не являющихся Singleton’ами.

Листинг 8

>class base {

>protected:

> virtual ~base(){}> //гарантируем удаление только через FreeInst()

>public:

> virtual void Do1()=0;

virtual void FreeInst(){delete this;}

>};


>class Simple: public base {

>protected:

> ~Simple () {printf("Simple::~Simple\n");}

>public:

> void Do1(){printf("Simple::Do1\n");}

>};


>class Singleton: public base {

> static Singleton* _self;

> static int _refcount;

>protected:

> Singleton(){}

> ~Singleton () {printf("Singleton::~Singleton\n");}

>public:

> static Singleton* Instance() {

>  if(!_self) _self = new Singleton ();

>  _refcount++;

>  return _self;

> }

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

>void Do1(){printf("Singleton::Do1\n");}

>};


>Singleton* Singleton::_self=NULL;

>int Singleton:: _refcount=0;


>class Client {

> base *objs[2];

> int ind;

>public:

> Client(){>  objs[0]=NULL;objs[1]=NULL;ind=0; }

> ~Client() {

>  for(int i=0;iFreeInst();

> }

> void Add(base *p){if(ind<2) objs[ind++]=p;}

> void Do() {

>  for(int i=0;iDo1();

> }

>};


>void main() {

> Client cl;

> cl.Add(Singleton::Instance());

> cl.Add(new Simple());

>cl.Do();

>}


результат работы программы:


Singleton::Do1 Simple::Do1 Singleton::~Singleton Simple::~Simple


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

Применение шаблонов языка C++.

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

листинг 9

>template

>class Singleton {

> static T* _self;

> static int _refcount;

>protected:

> Singleton(){}

> virtual ~Singleton(){_self=NULL;}

>public:

> static T* Instance();

> void FreeInst();

>};


>template

>T* Singleton::_self = NULL;


>template

>int Singleton::_refcount=0;


>template

>T* Singleton::Instance() {

> if(!_self) _self=new T;

> _refcount++;

> return _self;

>}


>template

>void Singleton::FreeInst() {

> if(--_refcount==0) delete this;

>}


>class Derived: public Singleton {

>protected:

> Derived(){}

> friend class Singleton;


стр.

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