|
Программирование >> Разработка устойчивых систем
Синглет и его разновидности Вероятно, простейшим паттерном в книге БЧ является Синглет, гарантирующий существование единственного экземпляра класса. Следующая программа показывает, как реализовать Синглет на С++: : C10:SingletonPattern.cpp linclude <iostream> using namespace std: class Singleton { static Singleton s: int i: Singleton(int x) : i(x) {} Singleton& operator=(Singleton&): Запрещено Singleton(const SingletonS): Запрещено public: static Singleton& instanceO { return s: } int getValueO { return i: } void setValueCint x) { i = x: } Singleton Singleton::s(47): int mainO { Singleton& s = Singleton::instanceO: cout s.getValueO endl: Singleton& s2 = Singleton::instanceO: s2.setValue(9): cout s.getValueO endl: } III:- Ключевой принцип создания Синглета состоит в том, что прикладной программист никак не может повлиять на жизненный цикл объекта. Для этого следует объявить все конструкторы закрытыми и предотвратить любые попытки компилятора генерировать конструктор. Обратите внимание: копирующий конструктор и оператор присваивания (для которых реализация специально не определяется, пото- int mainO { Filler filler: CollectingParameter cp: filler.f(cp) filler.g(cp) filler.h(cp); vector<string>::iterator it - cp.beginO: while(it != cp.endO) cout *it++ : cout endl: } III:- Накопитель должен обладать средствами сохранения или вставки новых значений (кстати, Посыльный по определению может использоваться в качестве На копителя). Принципиально здесь то, что Накопитель поочередно передается нескольким функциям и модифицируется ими. Стандарт С++ гласит: Единица трансляции не должна содержать более одного определения любой переменной, функции, класса, перечисляемого типа или шаблона... Каждая программа содержит ровно одно определение каждой неподставляемой функции или объекта, используемого в этой программе . му что они никогда не вызываются) объявляются закрытыми. Тем самым предотвращаются любые попытки создания копий. Вы также должны выбрать способ создания объекта. В нашем случае объект создается статически, но возможно и другое решение: подождать, пока прикладной программист запросит объект, и создать его по требованию. Такая методика называется отложенной инициализацией и имеет смысл только в том случае, если создание объекта обходится дорого и объект используется не всегда. Если вместо ссылки вернуть указатель, пользователь может случайно вызвать для него оператор delete, поэтому приведенная ранее реализация считается наиболее безопасной (проблема также решается объявлением деструктора закрытым или защищенным). В любом случае данные объекта должны быть закрытыми. Доступ к данным осуществляется через открытые функции класса. В нашем примере функция instance() возвращает ссылку на объект Singleton. Остальные функции (getValueO и setValue()) образуют привычный интерфейс доступа. В принципе эта методика не ограничивается лишь созданием одного объекта -она также позволяет создать ограниченный пул объектов, но тогда вы столкнетесь с проблемой организации совместного использования объектов в пуле. В этом случае можно создать решение с входным и выходным контролем общих объектов. Любой вложенный статический объект внутри класса выражает концепцию Синглета: он существует в одном и только одном экземпляре. В каком-то смысле язык обеспечивает прямую поддержку синглетности , которую мы регулярно применяем. Но при использовании статических объектов - как членов класса, так и внешних - возникает одна проблема, связанная с порядком инициализации (эта тема рассматривалась в первом томе). Если один статический объект зависит от другого, очень важно, чтобы эти объекты инициализировались в правильном порядке. В первом томе было показано, как управлять порядком инициализации, определяя статический объект в функции. При этом инициализация объекта откладывается до первого вызова функции. Если функция возвращает ссылку на статический объект, фактически получается тот же Синглет, но без хлопот с инициализацией статических объектов. Допустим, вы хотите создать файл журнала при первом вызове функции, возвращающей ссылку на этот файл. Задача решается следующим заголовочным файлом: : C10:LogFile.h #ifndef LOGFILE H #define LOGFILE H #include <fstream> std:: of streams logfileO: lendif LOGFILE H /:- Реализация не должна быть подставляемой, потому что это означало бы, что вся функция вместе с определением статического объекта дублируется во всех единицах трансляции, в которые она включается, а это привело бы к нарушению правила единственного определения С++. Все попытки управлять порядком инициализации наверняка кончатся провалом (и скорее всего, самым неочевидным и с трудноуловимыми причинами). Итак, реализация должна быть отдельной: Также называемой Синглетом Мейерса по имени автора Скотта Мейерса (Scott Meyers). : С10:1одРПе.срр {0} linclude LogFile.h std: :ofstream& logfileO { static std::ofstream logCLogfile.log ): return log: } III:- Теперь инициализация объекта log откладывается до первого вызова logfi*le(). Допустим, вы создали функцию: : C10:UseLogl.h lifndef USEL0G1 H Idefine USEL0G1 H void fO: lendif USEL0G1 H III:-B реализации этой функции имеется вызов logfile(): : C10:UseLogl.cpp {0} linclude UseLogl.h linclude LogFile.h void fO { logfileO FILE std::endl: } III:- Если повторно вызвать функцию logfile() в другом файле, как показано ниже, то объект log создается лишь после первого вызова f(): : C10:UseLog2.cpp {L} LogFile UseLogl linclude UseLogl.h linclude LogFile.h using namespace std: void gO { logfileO FILE endl: int mainO { fO; } / Создание статического объекта внутри функции класса легко объединяется с син-глетным классом. Ниже приводится новая версия профаммы SingletonPattern.cpp с применением этой методики: : C10:SingletonPattern2.cpp Синглет Мейерса linclude <iostream> using namespace std: class Singleton { int i: Singleton(int x) : i(x) { } void operator=(Singleton&): Singleton(const SingletonS): public: static Singleton& instanceO { static Singleton s(47): return s:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |