Программирование >>  Разработка устойчивых систем 

1 ... 150 151 152 [ 153 ] 154 155 156 ... 196


int getValueO { return 1; } void setValueCint x) { 1 = x: }

int mainO {

Sing1eton& s = Singleton::instance():

cout s.getValueO endl:

Singleton& s2 = Singleton::instance():

s2.setValue(9):

cout s.getValueO endl: } III:-

Особенно интересная ситуация возникает тогда, когда два Синглета зависят друг от друга:

: СЮ: Functi onStati cSi ngl eton. cpp

class Singletonl { SingletonlO {} public: static Singletonl& refO { static Singletonl single: return single;

class Singleton2 { Singletonl& si:

Singleton2(Singletonl& s) : sKs) {} public: static Singleton2& refO {

static Singleton2 single(Singletonl::ref()):

return single:

Singletonl& fO { return si; }

int mainO {

Singletonl& si = Singleton2::ref().f(): } III:-

Вызов Singleton2::ref() приводит к созданию синглетного объекта Singleton2. В процессе создания вызывается функция Singletonl::ref(), а это требует создания синглетного объекта Singletonl. Такая методика не зависит от порядка компоновки или загрузки, поэтому программист гораздо лучше контролирует процесс инициализации, что уменьшает количество проблем.

В другой разновидности данного паттерна синглетность объекта отделяется от его реализации. Для решения этой задачи используется механизм псевдорекурсии, упоминавшийся в главе 5:

: C10:CuriousSingleton.cpp

Отделение класса от его синглетности (почти)

linclude <iostream>

using namespace std;

tempiate<class T> class Singleton { Singleton(const Singleton&):



Singletons operator=(const SingletonS): protected: SingletonО {} virtual -SingletonO {} public: static T& instanceO { static T thelnstance: return thelnstance:

Пример класса, преобразуемого в Синглет class MyClass : public Singleton<MyClass> {

int x: protected:

friend class Singleton<MyClass>:

MyClassO{ X = 0: } public:

void setValueCint n) { x n: } int getValueO const { return x: }

int mainO { MyClassS m = MyClass::instanceO: cout m.getValueО endl: m.setValue(l):

cout m.getValueO endl: } III:-

Чтобы сделать класс MyClass синглетным, мы решили следующие задачи.

1. Объявили его конструктор закрытым или защищенным.

2. Объявили класс Singleton<MyClass> дружественным.

3. Объявили класс MyClass производным от Singleton<MyClass>.

Рекурсия на шаге 3 кажется невозможной, но как объяснялось в главе 5, она работает, поскольку в шаблоне Singleton существует только статическая зависимость от аргумента. Иначе говоря, компилятор может генерировать код Singleton<MyClass>, потому что он не зависит от размера MyClass. Информация о размере MyClass становится необходимой только позднее, при первом вызове функции Singleton<MyClass>::instance(), но к этому времени класс MyClass уже откомпилирован, а его размер известен.

Интересно, насколько нетривиальным может оказаться даже такой простой паттерн, как Синглет - а ведь мы даже не начинали рассматривать вопросы безопасности программных потоков. И последнее, Синглет следует применять осмотрительно. Действительно синглетные объекты встречаются редко, а задействовать Синглет для замены глобальной переменной - последнее дело.

Команда

Со структурной точки зрения паттерн Команда (Commanci) очень прост, однако он помогает ослабить привязку компонентов программы, а следовательно, делает программу более понятной.



В своей книге Advanced С++: Programming Styles and Idioms (Addison Wesley, 1992) Джим Коплин (Jim Coplien) вводит термин функтор - объект, предназначенный только для инкапсуляции функции (поскольку этот термин также встречается в математике, мы остановимся на более однозначном термине объект функции). Этот объект нужен, чтобы отделить выбор вызываемой функции от места ее вызова.

В книге БЧ объект функции упоминается, но не используется. С другой стороны, концепция объектов функций повторяется в нескольких рассматриваемых паттернах.

Команда представляет собой объект функции в его изначальном смысле - это функция, оформленная в виде объекта. Инкапсулируя функцию в объекте, можно передать ее другим функциям или объектам в качестве параметра, приказывая им выполнить конкретную операцию в процессе обработки запроса. Можно сказать, что Команда является частным случаем Посыльного, в котором передаются не данные, а операции.

: ClOiCommandPattern.cpp #1 nclude <iostream> #1 nclude <vector> using namespace std:

class Command { public:

virtual void executeO = 0:

class Hello : public Command { public:

void executeO { cout Hello : }

class World : public Command { public:

void executeO { cout World! : }

class lAm : public Command { public:

void executeO { cout Im the command pattern! : }

Объект для хранения набора команд: class Macro {

vector<Command*> commands: public:

void add(Command* c) { commands.push back(c): } void runO {

vector<Command*>::iterator it = commands.begin(): whileOt != commands, end О) (*it++)->execute():

int mainO { Macro macro: macro.add(new Hello):



1 ... 150 151 152 [ 153 ] 154 155 156 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.066
При копировании материалов приветствуются ссылки.
Яндекс.Метрика