#pragma once #ifndef TCG_OBSERVER_NOTIFIER_H #define TCG_OBSERVER_NOTIFIER_H // tcg includes #include "base.h" // STD includes #include /*! \file tcg_observer_notifier.h \brief This file contains the barebone of an elementary, classical implementation of the Observer pattern requiring derivation. \details This is intended as a convenient and lightweight predefined implementation when hardwiring the Observer pattern in a known class using derivation. Observe that this implementation does not deal with the actual notifications forwarding - it just manages the set of observers/notifiers in a notifier/observer instance. No multithreading is taken into consideration. \remark See elsewhere for more advanced implementations. */ namespace tcg { //************************************************************************ // Observer/notifier base polymorphic classes //************************************************************************ class observer_base; class notifier_base; //------------------------------------------------------------ class observer_base { public: virtual ~observer_base() {} virtual void attach(notifier_base *notifier) = 0; //!< Adds the specified notifier to the internal set of notifiers. virtual void detach(notifier_base *notifier) = 0; //!< Removes the specified notifier from the internal set of notifiers. }; //------------------------------------------------------------ class notifier_base { public: virtual ~notifier_base() {} virtual void attach(observer_base *observer) = 0; //!< Adds the specified observer to the internal set of observers. virtual void detach(observer_base *observer) = 0; //!< Removes the specified observer from the internal set of observers. }; //************************************************************************ // Observer/notifier with a single interacting object //************************************************************************ template class observer_single : public noncopyable { Notifier *m_notifier; // Not owned public: typedef Notifier notifier_type; public: observer_single() : m_notifier() {} ~observer_single() { if (m_notifier) static_cast(m_notifier)->detach(this); // The detaching function is most probably \a private in } // reimplemented notifier classes (like in this observer). // Besides, it would be a virtual function call anyway. notifier_type *notifier() const { return m_notifier; } private: void attach(notifier_base *notifier) { assert(notifier && !m_notifier); m_notifier = static_cast(notifier); } void detach(notifier_base *notifier) { assert(m_notifier && m_notifier == static_cast(notifier)); m_notifier = 0; } }; //------------------------------------------------------------ template class notifier_single : public noncopyable { Observer *m_observer; // Not owned public: typedef Observer observer_type; public: notifier_single() : m_observer() {} ~notifier_single() { if (m_observer) static_cast(m_observer)->detach(this); } observer_type *observer() const { return m_observer; } void addObserver(observer_type *observer) { notifier_single::attach(observer); // No reason to go polymorphic here - it's this very class. static_cast(observer)->attach(this); // However, here it's necessary - like above, downcast to } // the very base. void removeObserver(observer_type *observer) { static_cast(observer)->detach(this); notifier_single::detach(observer); } private: void attach(observer_base *observer) { assert(observer && !m_observer); m_observer = static_cast(observer); } void detach(observer_base *observer) { assert(m_observer && m_observer == static_cast(observer)); m_observer = 0; } }; //************************************************************************ // Observer/notifier with multiple interacting objects //************************************************************************ template > class observer : public noncopyable { Set m_notifiers; // Not owned public: typedef Notifier notifier_type; typedef Set notifiers_container; public: ~observer() { typename Set::iterator nt, nEnd = m_notifiers.end(); for (nt = m_notifiers.begin(); nt != nEnd; ++nt) static_cast(*nt)->detach(this); } const notifiers_container ¬ifiers() const { return m_notifiers; } private: void attach(notifier_base *notifier) { assert(notifier); m_notifiers.insert(static_cast(notifier)); } void detach(notifier_base *notifier) { assert(!m_notifiers.empty()); m_notifiers.erase(static_cast(notifier)); } }; //------------------------------------------------------------ template > class notifier : public noncopyable { Set m_observers; // Not owned public: typedef Observer observer_type; typedef Set observers_container; public: ~notifier() { typename Set::iterator ot, oEnd = m_observers.end(); for (ot = m_observers.begin(); ot != oEnd; ++ot) static_cast(*ot)->detach(this); } const observers_container &observers() const { return m_observers; } void addObserver(observer_type *observer) { notifier::attach(observer); static_cast(observer)->attach(this); } void removeObserver(observer_type *observer) { static_cast(observer)->detach(this); notifier::detach(observer); } private: void attach(observer_base *observer) { assert(observer); m_observers.insert(static_cast(observer)); } void detach(observer_base *observer) { assert(!m_observers.empty()); m_observers.erase(static_cast(observer)); } }; } // namespace tcg #endif // TCG_OBSERVER_NOTIFIER_H