|
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 |
|
|
Shinya Kitaoka |
120a6e |
namespace tcg {
|
|
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 |
|
|
Shinya Kitaoka |
120a6e |
class observer_base {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
virtual ~observer_base() {}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
virtual void attach(notifier_base *notifier) = 0; //!< Adds the specified
|
|
Shinya Kitaoka |
38fd86 |
//! notifier to the internal
|
|
Shinya Kitaoka |
38fd86 |
//! set of notifiers.
|
|
Shinya Kitaoka |
120a6e |
virtual void detach(notifier_base *notifier) = 0; //!< Removes the specified
|
|
Shinya Kitaoka |
38fd86 |
//! notifier from the
|
|
Shinya Kitaoka |
38fd86 |
//! internal set of
|
|
Shinya Kitaoka |
38fd86 |
//! notifiers.
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class notifier_base {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
virtual ~notifier_base() {}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
virtual void attach(observer_base *observer) = 0; //!< Adds the specified
|
|
Shinya Kitaoka |
38fd86 |
//! observer to the internal
|
|
Shinya Kitaoka |
38fd86 |
//! set of observers.
|
|
Shinya Kitaoka |
120a6e |
virtual void detach(observer_base *observer) = 0; //!< Removes the specified
|
|
Shinya Kitaoka |
38fd86 |
//! observer from the
|
|
Shinya Kitaoka |
38fd86 |
//! internal set of
|
|
Shinya Kitaoka |
38fd86 |
//! 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>
|
|
Shinya Kitaoka |
120a6e |
class observer_single : public noncopyable<base> {
|
|
Shinya Kitaoka |
120a6e |
Notifier *m_notifier; // Not owned
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
typedef Notifier notifier_type;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
observer_single() : m_notifier() {}
|
|
Shinya Kitaoka |
120a6e |
~observer_single() {
|
|
Shinya Kitaoka |
120a6e |
if (m_notifier)
|
|
Shinya Kitaoka |
120a6e |
static_cast<notifier_base *="">(m_notifier)</notifier_base>
|
|
Shinya Kitaoka |
120a6e |
->detach(
|
|
Shinya Kitaoka |
120a6e |
this); // The detaching function is most probably \a private in
|
|
Shinya Kitaoka |
120a6e |
} // reimplemented notifier classes (like in this observer).
|
|
Shinya Kitaoka |
120a6e |
// Besides, it would be a virtual function call anyway.
|
|
Shinya Kitaoka |
120a6e |
notifier_type *notifier() const { return m_notifier; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
void attach(notifier_base *notifier) {
|
|
Shinya Kitaoka |
120a6e |
assert(notifier && !m_notifier);
|
|
Shinya Kitaoka |
120a6e |
m_notifier = static_cast<notifier *="">(notifier);</notifier>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void detach(notifier_base *notifier) {
|
|
Shinya Kitaoka |
120a6e |
assert(m_notifier && m_notifier == static_cast<notifier *="">(notifier));</notifier>
|
|
Shinya Kitaoka |
120a6e |
m_notifier = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
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>
|
|
Shinya Kitaoka |
120a6e |
class notifier_single : public noncopyable<base> {
|
|
Shinya Kitaoka |
120a6e |
Observer *m_observer; // Not owned
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
typedef Observer observer_type;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
notifier_single() : m_observer() {}
|
|
Shinya Kitaoka |
120a6e |
~notifier_single() {
|
|
Shinya Kitaoka |
120a6e |
if (m_observer) static_cast<observer_base *="">(m_observer)->detach(this);</observer_base>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
observer_type *observer() const { return m_observer; }
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void addObserver(observer_type *observer) {
|
|
Shinya Kitaoka |
120a6e |
notifier_single::attach(
|
|
Shinya Kitaoka |
120a6e |
observer); // No reason to go polymorphic here - it's this very class.
|
|
Shinya Kitaoka |
120a6e |
static_cast<observer_base *="">(observer)->attach(</observer_base>
|
|
Shinya Kitaoka |
120a6e |
this); // However, here it's necessary - like above, downcast to
|
|
Shinya Kitaoka |
120a6e |
} // the very base.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void removeObserver(observer_type *observer) {
|
|
Shinya Kitaoka |
120a6e |
static_cast<observer_base *="">(observer)->detach(this);</observer_base>
|
|
Shinya Kitaoka |
120a6e |
notifier_single::detach(observer);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
void attach(observer_base *observer) {
|
|
Shinya Kitaoka |
120a6e |
assert(observer && !m_observer);
|
|
Shinya Kitaoka |
120a6e |
m_observer = static_cast<observer *="">(observer);</observer>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void detach(observer_base *observer) {
|
|
Shinya Kitaoka |
120a6e |
assert(m_observer && m_observer == static_cast<observer *="">(observer));</observer>
|
|
Shinya Kitaoka |
120a6e |
m_observer = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
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
|
|
Shinya Kitaoka |
120a6e |
typename Set = std::set<notifier *="">></notifier>
|
|
Shinya Kitaoka |
120a6e |
class observer : public noncopyable<base> {
|
|
Shinya Kitaoka |
120a6e |
Set m_notifiers; // Not owned
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
typedef Notifier notifier_type;
|
|
Shinya Kitaoka |
120a6e |
typedef Set notifiers_container;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
~observer() {
|
|
Shinya Kitaoka |
120a6e |
typename Set::iterator nt, nEnd = m_notifiers.end();
|
|
Shinya Kitaoka |
120a6e |
for (nt = m_notifiers.begin(); nt != nEnd; ++nt)
|
|
Shinya Kitaoka |
120a6e |
static_cast<notifier_base *="">(*nt)->detach(this);</notifier_base>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const notifiers_container ¬ifiers() const { return m_notifiers; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
void attach(notifier_base *notifier) {
|
|
Shinya Kitaoka |
120a6e |
assert(notifier);
|
|
Shinya Kitaoka |
120a6e |
m_notifiers.insert(static_cast<notifier *="">(notifier));</notifier>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void detach(notifier_base *notifier) {
|
|
Shinya Kitaoka |
120a6e |
assert(!m_notifiers.empty());
|
|
Shinya Kitaoka |
120a6e |
m_notifiers.erase(static_cast<notifier *="">(notifier));</notifier>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template
|
|
Shinya Kitaoka |
120a6e |
typename Set = std::set<observer *="">></observer>
|
|
Shinya Kitaoka |
120a6e |
class notifier : public noncopyable<base> {
|
|
Shinya Kitaoka |
120a6e |
Set m_observers; // Not owned
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
typedef Observer observer_type;
|
|
Shinya Kitaoka |
120a6e |
typedef Set observers_container;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
~notifier() {
|
|
Shinya Kitaoka |
120a6e |
typename Set::iterator ot, oEnd = m_observers.end();
|
|
Shinya Kitaoka |
120a6e |
for (ot = m_observers.begin(); ot != oEnd; ++ot)
|
|
Shinya Kitaoka |
120a6e |
static_cast<observer_base *="">(*ot)->detach(this);</observer_base>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const observers_container &observers() const { return m_observers; }
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void addObserver(observer_type *observer) {
|
|
Shinya Kitaoka |
120a6e |
notifier::attach(observer);
|
|
Shinya Kitaoka |
120a6e |
static_cast<observer_base *="">(observer)->attach(this);</observer_base>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void removeObserver(observer_type *observer) {
|
|
Shinya Kitaoka |
120a6e |
static_cast<observer_base *="">(observer)->detach(this);</observer_base>
|
|
Shinya Kitaoka |
120a6e |
notifier::detach(observer);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
void attach(observer_base *observer) {
|
|
Shinya Kitaoka |
120a6e |
assert(observer);
|
|
Shinya Kitaoka |
120a6e |
m_observers.insert(static_cast<observer *="">(observer));</observer>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void detach(observer_base *observer) {
|
|
Shinya Kitaoka |
120a6e |
assert(!m_observers.empty());
|
|
Shinya Kitaoka |
120a6e |
m_observers.erase(static_cast<observer *="">(observer));</observer>
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace tcg
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
#endif // TCG_OBSERVER_NOTIFIER_H
|