#include "DelegationPattern.h" #include <iostream> using namespace std; class Notifier : public INotifier { public: void NotifyAll(int j) { std::vector<IDelegate*>::iterator i = _delegates.begin(), iEnd = _delegates.end(); for (; i != iEnd; i++) { (*i)->Invoke(j++); } } }; class A : ISubscriber<A> { public: void SubscribeAll(INotifier* notifier) { Subscribe(notifier, &A::ma); Subscribe(notifier, &A::mb);}; void UnsubscribeAll(INotifier* notifier) { Unsubscribe(notifier, &A::ma); Unsubscribe(notifier, &A::mb);}; void UnsubscribeSecond(INotifier* notifier) { Unsubscribe(notifier, &A::mb);}; void SubscribeFirst(INotifier* notifier) { Subscribe(notifier, &A::ma);}; protected: void ma(int i) { cout << "A::ma(" << i << ") has been called" << endl;}; void mb(int i) { cout << "A::mb(" << i << ") has been called" << endl;}; }; class B : ISubscriber<B> { int _id; public: B(int id) : _id(id) {}; void SubscribeAll(INotifier* notifier) { Subscribe(notifier, &B::ma);}; void UnsubscribeAll(INotifier* notifier) { Unsubscribe(notifier, &B::ma);}; void ma(int i) { cout << "B(" << _id << ")::ma(" << i << ") has been called" << endl;}; }; int main() { Notifier notifier; A a; { B b1(1); B b2(2); a.SubscribeAll(¬ifier); notifier.NotifyAll(3); b1.SubscribeAll(¬ifier); notifier.NotifyAll(10); a.SubscribeFirst(¬ifier); a.UnsubscribeSecond(¬ifier); a.UnsubscribeSecond(¬ifier); b2.SubscribeAll(¬ifier); notifier.NotifyAll(21); } notifier.NotifyAll(30); }
Notifier is events source. It must be single instance and process all events.
Suppose you have 2 independent classes A and B, which want to receive some events from notifier. To achieve this goal they inherit ISubscriber interface and define inside themselves simple subscribe/unsubscribe methods. That's all. Program results are:
A::ma(3) has been called A::mb(4) has been called A::ma(10) has been called A::mb(11) has been called B(1)::ma(12) has been called A::ma(21) has been called B(1)::ma(22) has been called B(2)::ma(23) has been called A::ma(30) has been called
Here is the code that covers presented interfaces (DelegationPattern.h):
#ifndef _DELEGATION_PATTERN_INTERFACES_SVOLKOV_ #define _DELEGATION_PATTERN_INTERFACES_SVOLKOV_ #include <vector> #include <algorithm> class IDelegate; ///Simple notifier interface. class INotifier { public: void Subscribe(IDelegate* delegate) { _delegates.push_back(delegate);}; void Unsubscribe(IDelegate* delegate) { _delegates.erase(std::find(_delegates.begin(), _delegates.end(), delegate));}; protected: std::vector<IDelegate*> _delegates; }; /** Subscriber interface. @remarks Any class can become subscriber to register own methods as callbacks. */ template <class T> class ISubscriber { public: ///Destructor. virtual ~ISubscriber() = 0; ///Accepted arguments list for target callback method. typedef void (T::*CallbackMethod) (int); /** Register new delegate. @remarks Actually any other arguments can be added here to distinguish event type to subscribe etc. */ void Subscribe(INotifier* notifier, typename ISubscriber<T>::CallbackMethod method); /** Unregister delegate. */ void Unsubscribe(INotifier* notifier, typename ISubscriber<T>::CallbackMethod method); protected: std::vector<std::pair<INotifier*, IDelegate*> > _delegates; }; /** Delegate object interface. */ class IDelegate { public: ///Call. virtual void Invoke(int) = 0; }; /** Delegate object with callback method pointer. */ template <class T> class MethodDelegate : public IDelegate { template <typename U> friend class ISubscriber; protected: T* _object; typename ISubscriber<T>::CallbackMethod _method; public: ///Constructor. MethodDelegate(T* object, typename ISubscriber<T>::CallbackMethod method) : _object(object), _method(method) {}; ///Call. void Invoke(int); }; template<class T> void MethodDelegate<T>::Invoke(int i) { (_object->*_method)(i); } template <class T> ISubscriber<T>::~ISubscriber<T>() { std::vector<std::pair<INotifier*, IDelegate*> >::iterator i = _delegates.begin(), iEnd = _delegates.end(); for (; i != iEnd; i++) { i->first->Unsubscribe(i->second); delete(i->second); } } template <class T> void ISubscriber<T>::Subscribe(INotifier* notifier, typename ISubscriber<T>::CallbackMethod method) { std::vector<std::pair<INotifier*, IDelegate*> >::iterator i = _delegates.begin(), iEnd = _delegates.end(); for (; i != iEnd; i++) { if (i->first == notifier && ((MethodDelegate<T>*)i->second)->_method == method) return;//already subscribed } IDelegate* delegate = new MethodDelegate<T>((T*)this, method); _delegates.push_back(std::make_pair(notifier, delegate)); notifier->Subscribe(delegate); } template <class T> void ISubscriber<T>::Unsubscribe(INotifier* notifier, typename ISubscriber<T>::CallbackMethod method) { std::vector<std::pair<INotifier*, IDelegate*> >::iterator i = _delegates.begin(), iEnd = _delegates.end(); for (; i != iEnd; i++) { if (i->first == notifier && ((MethodDelegate<T>*)i->second)->_method == method) { i->first->Unsubscribe(i->second); delete i->second; _delegates.erase(i); return; } } } #endif
Make attention that it's only possible to define callback method with fixed arguments here (void method(int)), however it must be enough. In my program I used one (void method(object*)).
Also note that it's single-threaded solution. I'm going to post multi-threaded version later.
No comments:
Post a Comment