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