//: C09:ObservedFlower.cpp // From Thinking in C++, 2nd Edition // Available at http://www.BruceEckel.com // (c) Bruce Eckel 2000 // Copyright notice in Copyright.txt // Demonstration of "observer" pattern #include "Observable.h" #include #include #include #include using namespace std; class Flower { bool isOpen; public: Flower() : isOpen(false), openNotifier(this), closeNotifier(this) {} void open() { // Opens its petals isOpen = true; openNotifier.notifyObservers(); closeNotifier.open(); } void close() { // Closes its petals isOpen = false; closeNotifier.notifyObservers(); openNotifier.close(); } // Using the "inner class" idiom: class OpenNotifier; friend class Flower::OpenNotifier; class OpenNotifier : public Observable { Flower* parent; bool alreadyOpen; public: OpenNotifier(Flower* f) : parent(f), alreadyOpen(false) {} void notifyObservers(Argument* arg=0) { if(parent->isOpen && !alreadyOpen) { setChanged(); Observable::notifyObservers(); alreadyOpen = true; } } void close() { alreadyOpen = false; } } openNotifier; class CloseNotifier; friend class Flower::CloseNotifier; class CloseNotifier : public Observable { Flower* parent; bool alreadyClosed; public: CloseNotifier(Flower* f) : parent(f), alreadyClosed(false) {} void notifyObservers(Argument* arg=0) { if(!parent->isOpen && !alreadyClosed) { setChanged(); Observable::notifyObservers(); alreadyClosed = true; } } void open() { alreadyClosed = false; } } closeNotifier; }; class Bee { string name; // An "inner class" for observing openings: class OpenObserver; friend class Bee::OpenObserver; class OpenObserver : public Observer { Bee* parent; public: OpenObserver(Bee* b) : parent(b) {} void update(Observable*, Argument *) { cout << "Bee " << parent->name << "'s breakfast time!\n"; } } openObsrv; // Another "inner class" for closings: class CloseObserver; friend class Bee::CloseObserver; class CloseObserver : public Observer { Bee* parent; public: CloseObserver(Bee* b) : parent(b) {} void update(Observable*, Argument *) { cout << "Bee " << parent->name << "'s bed time!\n"; } } closeObsrv; public: Bee(string nm) : name(nm), openObsrv(this), closeObsrv(this) {} Observer& openObserver() { return openObsrv; } Observer& closeObserver() { return closeObsrv;} }; class Hummingbird { string name; class OpenObserver; friend class Hummingbird::OpenObserver; class OpenObserver : public Observer { Hummingbird* parent; public: OpenObserver(Hummingbird* h) : parent(h) {} void update(Observable*, Argument *) { cout << "Hummingbird " << parent->name << "'s breakfast time!\n"; } } openObsrv; class CloseObserver; friend class Hummingbird::CloseObserver; class CloseObserver : public Observer { Hummingbird* parent; public: CloseObserver(Hummingbird* h) : parent(h) {} void update(Observable*, Argument *) { cout << "Hummingbird " << parent->name << "'s bed time!\n"; } } closeObsrv; public: Hummingbird(string nm) : name(nm), openObsrv(this), closeObsrv(this) {} Observer& openObserver() { return openObsrv; } Observer& closeObserver() { return closeObsrv;} }; int main() { Flower f; Bee ba("A"), bb("B"); Hummingbird ha("A"), hb("B"); f.openNotifier.addObserver(ha.openObserver()); f.openNotifier.addObserver(hb.openObserver()); f.openNotifier.addObserver(ba.openObserver()); f.openNotifier.addObserver(bb.openObserver()); f.closeNotifier.addObserver(ha.closeObserver()); f.closeNotifier.addObserver(hb.closeObserver()); f.closeNotifier.addObserver(ba.closeObserver()); f.closeNotifier.addObserver(bb.closeObserver()); // Hummingbird B decides to sleep in: f.openNotifier.deleteObserver(hb.openObserver()); // Something changes that interests observers: f.open(); f.open(); // It's already open, no change. // Bee A doesn't want to go to bed: f.closeNotifier.deleteObserver( ba.closeObserver()); f.close(); f.close(); // It's already closed; no change f.openNotifier.deleteObservers(); f.open(); f.close(); } ///:~