#pragma once #include #include #include template class Observable; /** * An observer which can be mixed in as a baseclass. Implement onNotify as a method in your class. */ template class Observer { Observable *observed = NULL; public: virtual ~Observer(); /// Stop watching our current obserable void unobserve(); /// Start watching a specified observable void observe(Observable *o); private: friend class Observable; protected: /** * returns 0 if other observers should continue to be called * returns !0 if the observe calls should be aborted and this result code returned for notifyObservers **/ virtual int onNotify(T arg) = 0; }; /** * An observer that calls an arbitrary method */ template class CallbackObserver : public Observer { typedef int (Callback::*ObserverCallback)(T arg); Callback *objPtr; ObserverCallback method; public: CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {} protected: virtual int onNotify(T arg) { return (objPtr->*method)(arg); } }; /** * An observable class that will notify observers anytime notifyObservers is called. Argument type T can be any type, but for * performance reasons a pointer or word sized object is recommended. */ template class Observable { std::list *> observers; public: /** * Tell all observers about a change, observers can process arg as they wish * * returns !0 if an observer chose to abort processing by returning this code */ int notifyObservers(T arg) { for (typename std::list *>::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator) { int result = (*iterator)->onNotify(arg); if (result != 0) return result; } return 0; } private: friend class Observer; // Not called directly, instead call observer.observe void addObserver(Observer *o) { observers.push_back(o); } void removeObserver(Observer *o) { observers.remove(o); } }; template Observer::~Observer() { unobserve(); } template void Observer::unobserve() { if (observed) observed->removeObserver(this); observed = NULL; } template void Observer::observe(Observable *o) { // We can only watch one thing at a time assert(!observed); observed = o; o->addObserver(this); }