00001 /* 00002 * CntmLib - Подсчет ссылок, потоки, синхронизация, асинхронные процедуры, события 00003 * Copyright (c) 2005, Овсеевич Роман, CntmLib@mail.ru 00004 * _______________________________________________________________________________ 00005 * Разрешено свободное использование, копирование, распространение, изменение 00006 * (изменение сведений об авторских правах запрещено). Запрещена продажа и 00007 * включение всей библиотеки или ее частей в другие библиотеки. В сведениях об 00008 * авторских правах на программу (или сведениях о программе, об авторах, 00009 * использованных средствах разработки и т.д.) должна быть указана информация 00010 * о библиотеке CntmLib, ее авторе и, возможно, сайте или email'е. 00011 * Библиотека поставляется "как есть", без каких-либо гарантий со стороны автора. 00012 */ 00013 00014 #ifndef CNTM_DIRECTEVENT_H 00015 #define CNTM_DIRECTEVENT_H 00016 #include <Cntm/Utils/SignatureArgsCollector.h> 00017 #include <Cntm/Utils/SignatureInfo.h> 00018 #include <Cntm/Events/Internal/BasicDirectEvent.h> 00019 00020 namespace Cntm 00021 { 00022 00023 /** 00024 * Шаблонный класс обычного (прямого) события. 00025 * 00026 * Под событием, в данном случае, понимается способ оповещения сервером заинтересованной стороны (клиентов) об изменении своего состояния. Для того, чтобы клиент мог обрабатывать событие, он должен создать связь между объектом события и обработчиком. В качестве обработчиков вуступают методы объектов, т.е. обработчик задается указателем на объект и указателем на метод. С одним событием м.б. связано несколько обработчиков. При генерации события указываются аргументы, которые получат обработчики события (т.е. методы). В процессе генерации события быдут вызваны все обработчики с указанными аргументами. 00027 * 00028 * Класс Cntm::DirectEvent является шаблоном. В качестве параметра шаблона указывается сигнатура функции (т.е. без указания конкретного класса обработчика), которая будет использоваться при генерации события. Пример объвления события: 00029 * DirectEvent<void (int,const string&,Class1*,const Class2::Ptr&)> ChangeEvent; 00030 * Методы обработчиков должны иметь такую же сигнатуру, как и событие. При попытке связать событие с собработчиком с другой сигнатурой будет выдана ошибка компиляции, т.е. обеспечивается жесткая проверка типов. Возвращаемое значение (если его тип не void) при вызове обработчиков игнорируется. Обычно объект события объявляется как public поле объекта, генерирующего событие. 00031 * 00032 * Свзывание события с обработчиком осуществляется с помощью специального класса Cntm::EventLink (не является шаблоном). Что бы создать связь нужно создать объект этого класса и указать событие и обработчик (указатель на объект, указатель на метод). При уничтожении этого объекта связь будет автоматически разорвана. Также у этого класса есть метод Attach(), позволяющий изменить связь и имеющий такие же аргументы, что и конструктор (при этом старая связь разрывается и создается новая), а также метод Detach(), разрывающий текущую связь. Рассмотрим пример: 00033 * EventLink onChangeClass1(object1->ChangeEvent, this, &ThisClass::OnChangeClass1); 00034 * onChangeClass1.Attach(object2->ChangeEvent, this, &ThisClass::OnChangeClass2); 00035 * onChangeClass1.Detach(); 00036 * 00037 * Генерация события производится с помощью оператора operator() объекта события. В качестве аргументов этого оператора указываются аргументы, которые будут переданы обработчикам. Пример: 00038 * ChangeEvent(45, "Привет всем обработчикам", this, object2); 00039 * Вызов обработчиков прямого события происходит в момент генерации, т.е. в операторе operator() объекта события. 00040 * 00041 * Теперь подробнее о связях событий с обработчиками. Класс Cntm::EventLink имеет конструктор по умолчанию, который инициализирует пустую связь. Конструкторы связывания и методы Attach() имеют 3 параеметра. Рассмотрим их: 00042 * - 1 параметр Event - ссылка на объект события, т.е. должен передаваться объект события, с которым происходит связывание; 00043 * - 2 параметр Object - указатель на объект, который будет обрабатывать событие. Можно передвать либо ссылочный указатель либо обычный. Если указатель равен NULL, то генерируется исключение Cntm::NullArgException; 00044 * - 3 параметр Method - указатель на метод обработчика. Сигнатура метода должна полностью совпадать с сигнатурой события. 00045 * 00046 * Некоторые особенности работы. 00047 * 00048 * Время жизни объектов и подсчет ссылок. На объект, обрабатывающий событие (если это объект с подсчетом ссылок, наследующий Cntm::IRefObject) кол-во ссылок не увеличивается (что бы не препятствовать его удалению). Если после создания связи и до ее разрыва произойдет уничтожение объекта события, ничего страшного не случится, просто событие больше никогда не будет сгенерировано. Если во время существования связи произойдет уничтожение объкта обработчика, то это приведет к ошибкам выполнения, поэтому время жизни связи не должно превышать время жизни объекта обработчика. 00049 * 00050 * Процесс генерации события. Вызываются только те обработчики, которые были добавлены до генерации события. Если обработчик добавлен после генерации события (например, в одном из обработчиков), то добавленный обработчик вызван не будет. Если обработчик был удален в момент генерации до его вызова, то гарантируется, что он не будет вызван. Для объектов обработчиков, являющихся объектами с подсчетом ссылок: если на момент вызова обработчика события на объект не осталось ссылок, но он еще существует (находится в удаляемом состоянии, см. Cntm::IRefObject), то вызов обработчика произведен не будет, если вызов обработчика произведен, то гарантируется наличие хотя бы одной ссылки на объект обработчика до выхода из метода обработки. Исключения, сгенерированные в обработчиках, ни как не влияют на вызов других обработчиков, они просто игнорируются. Относительно аргументов события: 1. изменения аргументов коснутся всех обработчиков, которые будут вызваны после изменившего; 2. если аргумент передан по ссылке, то нет гарантии, что если обработчик произведет изменение этого аргумента, то это изменение отразится на исходном значении аргумента, которое было передано при генерации. 00051 * 00052 * Данный класс обеспечивает многопоточность. 00053 * @author Овсеевич Р. 00054 * \ingroup Events 00055 */ 00056 template < typename SignatureT > 00057 class DirectEvent: public SpecUtils::BasicDirectEvent, public SignatureArgsCollector < DirectEvent < SignatureT >, void, SignatureInfo < SignatureT >, SignatureInfo < SignatureT > ::argsCount > 00058 { 00059 private: 00060 00061 friend class SignatureArgsCollector<DirectEvent<SignatureT>, void, SignatureInfo<SignatureT>, SignatureInfo<SignatureT>::argsCount>; 00062 00063 typedef SignatureArgsCollectObjectBase <typename SignatureInfo<SignatureT>::Args> SignatureArgsCollectObject; 00064 typedef typename SignatureInfo<SignatureT>::template Method<HandlerType::Closure>::Pointer MethodPointer; 00065 00066 /** 00067 * Создать объект вызова. Просто создает в куче объект типа SignatureArgsCollectObject. Вызывается из AignatureArgsCollector::operator(). 00068 */ 00069 SignatureArgsCollectObject* CreateCollectObject() { return new SignatureArgsCollectObject; } 00070 00071 /** 00072 * Обработать объект вызова. Вызывается из AignatureArgsCollector::operator(). 00073 */ 00074 void ProcessCollectObject(SignatureArgsCollectObject* Object) 00075 { 00076 HandlersRegisterEx::Enumerator en = HandlersRegister()->GetEnumerator(false); // Можно использовать без проверки на NULL, т.к. этот случай блокируется NoNeedCreateCollectObject() - вызова ProcessCollectObject() не будет, если NoNeedCreateCollectObject вернет true (это произойдет, если HandlersRegister равен NULL). 00077 while (en.Next()) 00078 { 00079 if (en.Current()) // Если объект не в удаляемом состоянии - обрабатываем. 00080 { 00081 try 00082 { 00083 SignatureInfo<SignatureT>::MethodCall(en.Current().Object(), 00084 reinterpret_cast<MethodPointer>(en.Current().Method()), Object->Args()); 00085 } 00086 catch (...) 00087 { 00088 } 00089 } 00090 } 00091 delete Object; 00092 } 00093 00094 /** 00095 * Проверяет, нужно ли обрабатывать вызов для генерации события. Если обработчиков нет, то никаких действий не выполняется. Вызывается из AignatureArgsCollector::operator(). 00096 */ 00097 bool NoNeedCreateCollectObject() { return NoNeedCall(); } 00098 00099 /** 00100 * Ничего не делает. Нужна для AignatureArgsCollector::operator(). 00101 */ 00102 void NoneProcessCollectObject() {} 00103 }; 00104 00105 } 00106 00107 #endif //CNTM_DIRECTEVENT_H
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой 1.5.3 |