|
Shinya Kitaoka |
810553 |
#pragma once
|
|
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
|