Version 1 (modified by 12 years ago) ( diff ) | ,
---|
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 observables in turn have to sign on to the observer'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
- surround any code that makes notify-worthy changes with
OBSERVE;
andNOTIFY(channel);
withchannel
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 }; 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 } };