= Observer Howto = == Theory == The ''Observer'' pattern is a way of implementing a one-to-many dependency. There usually is one observable object automatically notifying multiple observer objects of its changes. For doing so the observer keeps a list of its observables. The observers in turn have to sign on to the observable's list. == Implementation == === Creating an observable === * derive the observable class from {{{Observable}}} * create an enum type with one element for each type of change about to occur * in the constructor call the {{{Observable}}} constructor giving a string name for your class * also in the constructor create the channels (see code below) * surround any code that makes notify-worthy changes with {{{OBSERVE;}}} and {{{NOTIFY(channel);}}} with {{{channel}}} the appropriate enum constant For example: {{{ class MyObservable : public Observable { public: enum NotificationType{ // should be public (the observer will want to use this type!) SomethingDone, OtherStuffDone, NotificationType_MAX }; MyObservable() : Observable("MyObservable") { Channels *OurChannel = new Channels; NotificationChannels.insert( std::make_pair(this, OurChannel) ); // add instance for each notification type for (size_t type = 0; type < NotificationType_MAX; ++type) OurChannel->addChannel(type); // other constructor stuff ... } .... void doSomeChanges() { OBSERVE; ... // do the actual changes NOTIFY(SomethingDone); // send notifications to all observers } }; }}} === Creating an observer === * derive the observer class from {{{Observer}}} * add a virtual member function {{{virtual void MyObserver::update(Observable *publisher);}}} to be called on changes * (''optionally'') add a virtual member function {{{virtual void MyObserver::recieveNotification(Observable *publisher, Notification_ptr notification);}}} to be called on changes with more information * add a virtual member function {{{virtual void MyObserver::subjectKilled(Observable *publisher);}}} to be called when the observable is deleted * signon... Simple example: {{{ class MyObserver : public Observer { public: MyObserver() { MyObservable *observable = ...; observable->signOn(this); } virtual ~MyObserver() { observable->signOff(this); } virtual void update(Observable *publisher) { // react to changes } virtual void subjectKilled(Observable *publisher){} }; }}} More complex example: {{{ class MyObserver : public Observer { public: MyObserver() { MyObservable *observable1 = ...; MyObservable *observable2 = ...; observable1->signOn(this); // receive all notifications observable2->signOn(this, MyObservable::SomethingChanged); select specific notifications observable2->signOn(this, MyObservable::OtherStuffChanged); } virtual ~MyObserver() { observable1->signOff(this); observable2->signOff(this); } virtual void update(Observable *publisher) { // react to any changes } virtual void recieveNotification(Observable *publisher, Notification_ptr notification) { if (notification->getChannelNo() == MyObservable::SomethingChanged){ // react to specific notification } } virtual void subjectKilled(Observable *publisher){} }; }}} == Caveats == Using {{{observableObject->signOff(this);}}} in the observer's destructor will cause a segfault in case the observable is deleted while the observer lives on. For rather short lived observables this has to be circumvented: {{{ class MyObserver : public Observer { MyObservable *observable; MyObserver() { observable = ...; observable->signOn(this); } virtual ~MyObserver() { if (observable) // only sign off if the observer still lives observable->signOff(this); } virtual void update(Observable *publisher) { // react to changes } virtual void subjectKilled(Observable *publisher) { observable = NULL; // don't sign off } }; }}}