2016-05-17 03:04:11 +12:00
|
|
|
#pragma once
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#ifndef TCG_OBSERVER_NOTIFIER_H
|
|
|
|
#define TCG_OBSERVER_NOTIFIER_H
|
|
|
|
|
|
|
|
// tcg includes
|
|
|
|
#include "base.h"
|
|
|
|
|
|
|
|
// STD includes
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\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 <I>does not deal with the
|
|
|
|
actual notifications forwarding</I> - 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.
|
|
|
|
*/
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
namespace tcg {
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//************************************************************************
|
|
|
|
// Observer/notifier base polymorphic classes
|
|
|
|
//************************************************************************
|
|
|
|
|
|
|
|
class observer_base;
|
|
|
|
class notifier_base;
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class observer_base {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
virtual ~observer_base() {}
|
|
|
|
|
|
|
|
virtual void attach(notifier_base *notifier) = 0; //!< Adds the specified
|
2016-06-20 14:23:05 +12:00
|
|
|
//! notifier to the internal
|
|
|
|
//! set of notifiers.
|
2016-06-15 18:43:10 +12:00
|
|
|
virtual void detach(notifier_base *notifier) = 0; //!< Removes the specified
|
2016-06-20 14:23:05 +12:00
|
|
|
//! notifier from the
|
|
|
|
//! internal set of
|
|
|
|
//! notifiers.
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
class notifier_base {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
virtual ~notifier_base() {}
|
|
|
|
|
|
|
|
virtual void attach(observer_base *observer) = 0; //!< Adds the specified
|
2016-06-20 14:23:05 +12:00
|
|
|
//! observer to the internal
|
|
|
|
//! set of observers.
|
2016-06-15 18:43:10 +12:00
|
|
|
virtual void detach(observer_base *observer) = 0; //!< Removes the specified
|
2016-06-20 14:23:05 +12:00
|
|
|
//! observer from the
|
|
|
|
//! internal set of
|
|
|
|
//! observers.
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//************************************************************************
|
|
|
|
// Observer/notifier with a single interacting object
|
|
|
|
//************************************************************************
|
|
|
|
|
|
|
|
template <typename Notifier = notifier_base, typename Base = observer_base>
|
2016-06-15 18:43:10 +12:00
|
|
|
class observer_single : public noncopyable<Base> {
|
|
|
|
Notifier *m_notifier; // Not owned
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef Notifier notifier_type;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
observer_single() : m_notifier() {}
|
|
|
|
~observer_single() {
|
|
|
|
if (m_notifier)
|
|
|
|
static_cast<notifier_base *>(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; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
void attach(notifier_base *notifier) {
|
|
|
|
assert(notifier && !m_notifier);
|
|
|
|
m_notifier = static_cast<Notifier *>(notifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach(notifier_base *notifier) {
|
|
|
|
assert(m_notifier && m_notifier == static_cast<Notifier *>(notifier));
|
|
|
|
m_notifier = 0;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
|
|
|
template <typename Observer = observer_base, typename Base = notifier_base>
|
2016-06-15 18:43:10 +12:00
|
|
|
class notifier_single : public noncopyable<Base> {
|
|
|
|
Observer *m_observer; // Not owned
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef Observer observer_type;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
notifier_single() : m_observer() {}
|
|
|
|
~notifier_single() {
|
|
|
|
if (m_observer) static_cast<observer_base *>(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_base *>(observer)->attach(
|
|
|
|
this); // However, here it's necessary - like above, downcast to
|
|
|
|
} // the very base.
|
|
|
|
|
|
|
|
void removeObserver(observer_type *observer) {
|
|
|
|
static_cast<observer_base *>(observer)->detach(this);
|
|
|
|
notifier_single::detach(observer);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
void attach(observer_base *observer) {
|
|
|
|
assert(observer && !m_observer);
|
|
|
|
m_observer = static_cast<Observer *>(observer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach(observer_base *observer) {
|
|
|
|
assert(m_observer && m_observer == static_cast<Observer *>(observer));
|
|
|
|
m_observer = 0;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//************************************************************************
|
|
|
|
// Observer/notifier with multiple interacting objects
|
|
|
|
//************************************************************************
|
|
|
|
|
|
|
|
template <typename Notifier = notifier_base, typename Base = observer_base,
|
2016-06-15 18:43:10 +12:00
|
|
|
typename Set = std::set<Notifier *>>
|
|
|
|
class observer : public noncopyable<Base> {
|
|
|
|
Set m_notifiers; // Not owned
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef Notifier notifier_type;
|
|
|
|
typedef Set notifiers_container;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
~observer() {
|
|
|
|
typename Set::iterator nt, nEnd = m_notifiers.end();
|
|
|
|
for (nt = m_notifiers.begin(); nt != nEnd; ++nt)
|
|
|
|
static_cast<notifier_base *>(*nt)->detach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
const notifiers_container ¬ifiers() const { return m_notifiers; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
void attach(notifier_base *notifier) {
|
|
|
|
assert(notifier);
|
|
|
|
m_notifiers.insert(static_cast<Notifier *>(notifier));
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach(notifier_base *notifier) {
|
|
|
|
assert(!m_notifiers.empty());
|
|
|
|
m_notifiers.erase(static_cast<Notifier *>(notifier));
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
|
|
|
template <typename Observer = observer_base, typename Base = notifier_base,
|
2016-06-15 18:43:10 +12:00
|
|
|
typename Set = std::set<Observer *>>
|
|
|
|
class notifier : public noncopyable<Base> {
|
|
|
|
Set m_observers; // Not owned
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef Observer observer_type;
|
|
|
|
typedef Set observers_container;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
~notifier() {
|
|
|
|
typename Set::iterator ot, oEnd = m_observers.end();
|
|
|
|
for (ot = m_observers.begin(); ot != oEnd; ++ot)
|
|
|
|
static_cast<observer_base *>(*ot)->detach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
const observers_container &observers() const { return m_observers; }
|
|
|
|
|
|
|
|
void addObserver(observer_type *observer) {
|
|
|
|
notifier::attach(observer);
|
|
|
|
static_cast<observer_base *>(observer)->attach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeObserver(observer_type *observer) {
|
|
|
|
static_cast<observer_base *>(observer)->detach(this);
|
|
|
|
notifier::detach(observer);
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
void attach(observer_base *observer) {
|
|
|
|
assert(observer);
|
|
|
|
m_observers.insert(static_cast<Observer *>(observer));
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach(observer_base *observer) {
|
|
|
|
assert(!m_observers.empty());
|
|
|
|
m_observers.erase(static_cast<Observer *>(observer));
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
} // namespace tcg
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
#endif // TCG_OBSERVER_NOTIFIER_H
|