Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 [ 45 ] 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

Реализация шаблона Singleton

Шаблон проектирования Singleton (Gamma et al, 1995) представляет собой уникальную комбинацию простого описания и сложной реализации. Об этом свидетельствуют многочисленные книги и журнальные публикации (например, Vlissides, 1996, 1998). Описание шаблона Singleton в книге Gamma et al. (1995) весьма просто: "Шаблон гарантирует, что класс имеет только один экземпляр и обеспечивает глобальный доступ к нему".

Синглтон - это улучшенный вариант глобальной переменной. Новшество заключается в том, что второй объект типа Singleton создать нельзя. Следовательно, синглтоны можно использовать в приложениях при моделировании типов, имеющих только один экземпляр, таких как Keyboard, Display, PrintManager и Systemclock. Создавать вторые экземпляры таких классов соверщенно неестественно и, кроме того, опасно.

Глобальный доступ имеет скрытые побочные последствия - с точки зрения клиента объект класса singleton владеет самим собой. Для создания объекта класса Singleton клиент ничего не должен делать. Следовательно, объект класса Singltone сам создает и разрушает себя. Управление продолжительностью жизни синглтона представляет собой головоломную задачу.

В этой главе обсуждаются наиболее важные вопросы, связанные с проектированием и реализацией разных вариантов класса Singleton в языке С++.

• Свойства, которые отличают синглтон от обычной глобальной переменной.

• Основные идиомы языка С++ для поддержки синглтонов.

• Обеспечение уникальности синглтона.

• Уничтожение синглтона и распознавание доступа после уничтожения.

• Усовершенствованное управление продолжительностью жизни объекта класса Singltone.

• Многопоточность.

Мы опишем способы решения перечисленных выше проблем, а затем применим их для реализации обобщенного шаблонного класса SingletonHolder.

"Оптимальной" реализации шаблона проектирования Singleton не существует. В зависимости от конкретной задачи наилучшими оказываются различные реализации, включая машинно-зависимые. Подход, описанный в этой главе, предназначен для разработки семейства реализаций на основе обобщенного скелета класса в духе проектирования на основе стратегий (глава 1). Класс SingletonHand оставляет также возможности для его расширения и настройки.

В конце этой главы мы разработаем шаблонный класс SingletonHolder, способный генерировать много синглтонов разного типа. Класс SingletonHolder предостав-



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

6.1. Статические данные + статические функции != синглтон

На первый взгляд кажется, что для создания класса singleton нужны лишь статические функции-члены и переменные-члены.

class Font {...};

class Printerport { ... };

class PrintJob { ... }

class MyOnlyPrinter {

public:

static void AddPrintJobCPrintJobA newjob) {

ifCprintQueue .emptyC) && printingPort .availableC)) printingPort . sendCnewjob.DataO);

else {

printQueue .pushCnewjob); .

private:

все данные являются статическими static std::queue<PrintJob> printQueue ; static printerport printingPort ; static Font defaultFont ;

PrintJob somePrintJobCMyDocument.txt"); MyOnlyPrinter::AddPrintJobCsomePrintJob);

Однако это решение в некоторых ситуациях имеет много недостатков. Основная проблема заключается в том, что статические функции не могут быть виртуальными, что не позволяет изменять поведение объекта при открытии кода класса MyOnlyPrinter.

Кроме того, инициализация и удаление объекта затрудняются. В классе MyOnlyPrinter нет конкретных точек, в которых инициализируются и удаляются данные, хотя эти задачи могут быть нетривиальными - например, переменная-член default-Font, может зависеть от скорости обмена данными порта, поведение которого описывается переменной printingPort .

Таким образом, реализация синглтонов сводится к созданию и управлению уникальным объектом, при этом создавать другие объекты такого типа запрещено.

На самом деле этот код иллюстрирует шаблон проектирования Monostate (Ball and Crawford, 1998).



6.2. Основные идиомы языка С++для поддержки синглтонов

Чаще всего синглтоны создаются с помощью вариаций следующей идиомы.

Заголовочный файл Singleton.h

class Singleton

public:

static Singleton* instanceC) Единственная точка доступа {

if (!pinstance )

plnstance = new singleton; return pinstance ;

... операции ... private:

SingletonC); предотвращает создание нового

объекта класса Singleton Singleton(const Sing1eton&); предотвращает создание

копии объекта класса singleton static Sing1eton&* plnstance ; Единственный экземпляр

Файл реализации Singleton.cpp Singleton* singleton::pinstance = 0;

Поскольку все конструкторы закрыты, код пользователя не может создать объект класса Singleton. Однако класс содержит функции-члены, в частности, функцию Instance, которые позволяют создавать объекты. Следовательно, требование уникальности объекта класса Singleton накладывается на этапе компиляции. В этом и заключается суть реализации щаблона проектирования Si ngl eton в языке С++.

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

Есть большое искушение упростить класс, заменив указатель plnstance в предыдущем примере полноценным объектом класса singleton.

Заголовочный файл Singleton.h class Singleton

public:

static Singleton* instanceC) Единственная точка доступа {

return &instance ;

int DoSomethingO; private:

static Singleton instance.;

Файл реализации singleton.cpp si ngleton singleton::instance ;

Это неудачное решение. Несмотря на то что переменная instance является статическим членом класса Singleton (как и указатель plnstance в предыдущем при-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 [ 45 ] 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105