#include #include #include // ==== Observer Pattern Framework ============================================ #include #include using namespace std; namespace FIXUP { // FIXUP Needed when using BC5.02 because mem_fun is not implemented. // FIXUP Needed when using VC5.0 because mem_fun implementatiom in // function.h has problems with member functions that return void. template class mem_fun_t: public unary_function { void(T::*pmf)(); public: explicit mem_fun_t(void(T::*p)()): pmf(p) { } void operator()(T* p) const { (p->*pmf)(); } }; template mem_fun_t mem_fun(void(T::*f)()) { return mem_fun_t(f); } } // END FIXUP // == Observer == class SubjectIsDestroyed {}; // Exception class Subject; class Observer { public: virtual void update()=0; virtual void destruct(); protected: Observer(Subject& s); virtual ~Observer(); const Subject* getPointerToSubject() const { if (pointerToSubject==0) throw SubjectIsDestroyed(); return pointerToSubject; } private: Subject* pointerToSubject; Observer(const Observer&); void operator=(const Observer&); }; // == Subject == class Subject { public: void attach(Observer* o) { observers.push_front(o); } void detach(Observer* o) { observers.remove(o); } protected: Subject() { } virtual ~Subject() { using FIXUP::mem_fun; for_each(observers.begin(), observers.end(), mem_fun(&Observer::destruct)); } void notify() const { using FIXUP::mem_fun; for_each(observers.begin(), observers.end(), mem_fun(&Observer::update)); } private: list observers; Subject(const Subject&); void operator=(const Subject&); }; inline Observer::Observer(Subject& s): pointerToSubject(&s) { pointerToSubject->attach(this); } inline Observer::~Observer() { if (pointerToSubject) pointerToSubject->detach(this); } inline void Observer::destruct() { pointerToSubject->detach(this); pointerToSubject=0; } // == Model == template class Model: public Subject { public: Model(): value(0) { } Model(const T& init): value(init) { } virtual void set(const T& v) { value=v; notify(); } virtual const T& get() const { return value; } protected: T value; }; // == CallOnwrite == template class CallOnWrite: public Observer { public: typedef void (C::*PF)(); CallOnWrite(Model& m, C* po, PF pfu): Observer(m), pointerToComponent(po), pointerToUpdateFunction(pfu) { } const Model& operator*() const { return static_cast&>(*getPointerToSubject()); } const Model* operator->() const { return static_cast*>(getPointerToSubject()); } protected: virtual void update() { (pointerToComponent->*pointerToUpdateFunction)(); } private: PF pointerToUpdateFunction; C* pointerToComponent; }; // ==== Application that uses the Classic Observer Pattern ==================== // == ConcreteSubjects == typedef Model Pin; typedef Model Register; // == ConcreteObservers == template class DecDisplay { public: DecDisplay(Model& m, const string& n): cow(m, this, &DecDisplay::update), name(n) { } private: void update() { cout<get()< > cow; string name; }; template class HexDisplay { public: HexDisplay(Model& m, const string& n): cow(m, this, &HexDisplay::update), name(n) { } private: void update() { cout<get()< > cow; string name; }; typedef DecDisplay DecRegisterDisplay; typedef HexDisplay HexRegisterDisplay; typedef DecDisplay PinDisplay; // == Simulator == class Simulator { public: Register pc; // program counter Pin pin1; void run() { for (short i(9); i<16; ++i) { if (i%5==0) pin1.set(!pin1.get()); pc.set(i); } } }; // == User Interface == void main() { Simulator s; DecRegisterDisplay d1(s.pc, "Program Counter"); { HexRegisterDisplay d2(s.pc, "Program Counter"); PinDisplay d3(s.pin1, "Pin 1"); s.run(); } s.run(); #ifdef __TURBOC__ cout<<"Press a key: "; cin.get(); #endif }