#pragma once
#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.
*/
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 <typename Notifier = notifier_base, typename Base = observer_base>
class observer_single : public noncopyable<Base>
{
Notifier *m_notifier; // Not owned
public:
typedef Notifier notifier_type;
public:
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; }
private:
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;
}
};
//------------------------------------------------------------
template <typename Observer = observer_base, typename Base = notifier_base>
class notifier_single : public noncopyable<Base>
{
Observer *m_observer; // Not owned
public:
typedef Observer observer_type;
public:
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);
}
private:
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;
}
};
//************************************************************************
// Observer/notifier with multiple interacting objects
//************************************************************************
template <typename Notifier = notifier_base, typename Base = observer_base,
typename Set = std::set<Notifier *>>
class observer : public noncopyable<Base>
{
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<notifier_base *>(*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 *>(notifier));
}
void detach(notifier_base *notifier)
{
assert(!m_notifiers.empty());
m_notifiers.erase(static_cast<Notifier *>(notifier));
}
};
//------------------------------------------------------------
template <typename Observer = observer_base, typename Base = notifier_base,
typename Set = std::set<Observer *>>
class notifier : public noncopyable<Base>
{
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<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);
}
private:
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));
}
};
} // namespace tcg
#endif // TCG_OBSERVER_NOTIFIER_H