172 lines
5.2 KiB
C++
172 lines
5.2 KiB
C++
|
|
// -*- C++ -*-
|
||
|
|
//
|
||
|
|
// METS lib source file - observer.h
|
||
|
|
//
|
||
|
|
/*
|
||
|
|
* Software License Agreement (BSD License)
|
||
|
|
*
|
||
|
|
* Copyright (c) 2006-2012, Mirko Maischberger <mirko.maischberger@gmail.com>
|
||
|
|
* All rights reserved.
|
||
|
|
*
|
||
|
|
* Redistribution and use in source and binary forms, with or without
|
||
|
|
* modification, are permitted provided that the following conditions
|
||
|
|
* are met:
|
||
|
|
*
|
||
|
|
* * Redistributions of source code must retain the above copyright
|
||
|
|
* notice, this list of conditions and the following disclaimer.
|
||
|
|
* * Redistributions in binary form must reproduce the above
|
||
|
|
* copyright notice, this list of conditions and the following
|
||
|
|
* disclaimer in the documentation and/or other materials provided
|
||
|
|
* with the distribution.
|
||
|
|
*
|
||
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef METS_OBSERVER_HH_
|
||
|
|
#define METS_OBSERVER_HH_
|
||
|
|
|
||
|
|
#include <set>
|
||
|
|
#include <algorithm>
|
||
|
|
|
||
|
|
namespace mets {
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
class observer; // forward declaration
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
class subject; // forward declaration
|
||
|
|
|
||
|
|
///
|
||
|
|
/// @brief Functor class to update observers with a for_each,
|
||
|
|
/// only intended for internal use.
|
||
|
|
///
|
||
|
|
template<typename observed_subject>
|
||
|
|
class update_observer
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
/// @brief Ctor.
|
||
|
|
update_observer(observed_subject* who) : who_m(who) {}
|
||
|
|
/// @brief Subscript operator to update an observer.
|
||
|
|
void
|
||
|
|
operator()(observer<observed_subject>* o) { o->update(who_m); }
|
||
|
|
private:
|
||
|
|
update_observer();
|
||
|
|
observed_subject* who_m;
|
||
|
|
};
|
||
|
|
|
||
|
|
///
|
||
|
|
/// @brief template class for subjects (cfr. Observer Design Pattern).
|
||
|
|
///
|
||
|
|
/// You must declare the subject of the observations with:
|
||
|
|
///
|
||
|
|
/// class my_observed_sbj : public subject<my_observed_sbj>
|
||
|
|
///
|
||
|
|
/// Than you should call notify() manually or automatically
|
||
|
|
/// from every method that changes the subject status.
|
||
|
|
///
|
||
|
|
/// Only attached observers (cfr. attach() and detach() methods)
|
||
|
|
/// will be notified.
|
||
|
|
///
|
||
|
|
template<typename observed_subject>
|
||
|
|
class subject
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual
|
||
|
|
~subject() {};
|
||
|
|
/// @brief Attach a new observer to this subject.
|
||
|
|
///
|
||
|
|
/// @param o: a new observer for this subject.
|
||
|
|
/// if the observer was already present
|
||
|
|
/// nothing happens.
|
||
|
|
virtual void
|
||
|
|
attach(observer<observed_subject>& o);
|
||
|
|
/// @brief Detach a new observer to this subject.
|
||
|
|
///
|
||
|
|
/// @param o: observer to detach from this subject.
|
||
|
|
/// if the observer "o" was not present
|
||
|
|
/// nothing happens.
|
||
|
|
virtual void
|
||
|
|
detach(observer<observed_subject>& o);
|
||
|
|
/// @brief Notify all attached observers.
|
||
|
|
///
|
||
|
|
/// When this method is called every
|
||
|
|
/// observed_subject#update method is called
|
||
|
|
/// and "this" subject is passed as a param.
|
||
|
|
///
|
||
|
|
virtual void
|
||
|
|
notify();
|
||
|
|
protected:
|
||
|
|
subject();
|
||
|
|
std::set<observer<observed_subject>*> observers_m;
|
||
|
|
};
|
||
|
|
|
||
|
|
///
|
||
|
|
/// @brief Template base class for the observers of some observed_subject
|
||
|
|
///
|
||
|
|
/// You should declare a new observer type of some my_subject this way:
|
||
|
|
///
|
||
|
|
/// class my_observer : public observer<my_subject>
|
||
|
|
///
|
||
|
|
/// Every time notify() is called on the subject every attached
|
||
|
|
/// observer is updated.
|
||
|
|
///
|
||
|
|
template<typename observed_subject>
|
||
|
|
class observer
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual
|
||
|
|
~observer() {};
|
||
|
|
/// @brief This method is automatically called when this
|
||
|
|
/// observer is attached to a "notified" subject.
|
||
|
|
///
|
||
|
|
/// @param subject: The subject that was notified and that
|
||
|
|
/// called our update method.
|
||
|
|
virtual void
|
||
|
|
update(observed_subject*) = 0;
|
||
|
|
protected:
|
||
|
|
observer() {};
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
// Implementation of the template methods in STL
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
subject<observed_subject>::subject()
|
||
|
|
: observers_m() { }
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
void
|
||
|
|
subject<observed_subject>::attach(observer<observed_subject>& o)
|
||
|
|
{ observers_m.insert(&o); }
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
void
|
||
|
|
subject<observed_subject>::detach(observer<observed_subject>& o)
|
||
|
|
{ observers_m.erase(&o); }
|
||
|
|
|
||
|
|
template<typename observed_subject>
|
||
|
|
void
|
||
|
|
subject<observed_subject>::notify()
|
||
|
|
{
|
||
|
|
// upcast the object to the real observer_subject type
|
||
|
|
observed_subject* real_subject = static_cast<observed_subject*>(this);
|
||
|
|
std::for_each(observers_m.begin(), observers_m.end(),
|
||
|
|
update_observer<observed_subject>(real_subject));
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif // METS_OBSERVER_HH_
|