|
Программирование >> Разработка устойчивых систем
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):
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.066
При копировании материалов приветствуются ссылки. |