clear();
Chapter 16: Design Patterns
923
}
virtual int countObservers() {
return observers.size();
}
virtual bool hasChanged() { return changed; }
// If this object has changed, notify all
// of its observers:
virtual void notifyObservers(Argument* arg=0) {
if(!hasChanged()) return;
std::set<Observer*>::iterator it;
for(it = observers.begin();
it != observers.end(); it++)
(*it)->update(this, arg);
clearChanged(); // Not "changed" anymore
}
};
#endif // OBSERVABLE_H ///:~
Again, the design here is more elaborate than is necessary; as long as there’s a way to register an Observer with an Observable and for the Observable to update its Observers, the set of member functions doesn’t matter. However, this design is intended to be reusable (it was
lifted from the design used in the Java standard library). As mentioned elsewhere in the book, there is no support for multithreading in the Standard C++ libraries, so this design would need to be modified in a multithreaded environment.
Observable has a flag to indicate whether it’s been changed. In a simpler design, there would be no flag; if something happened, everyone would be notified. The flag allows you to wait,
and only notify the Observers when you decide the time is right. Notice, however, that the control of the flag’s state is protected, so that only an inheritor can decide what constitutes a change, and not the end user of the resulting derived Observer class.
The collection of Observer objects is kept in a set<Observer*> to prevent duplicates; the set insert( ), erase( ), clear( ) and size( ) functions are exposed to allow Observers to be added and removed at any time, thus providing runtime flexibility.
Most of the work is done in notifyObservers( ). If the changed flag has not been set, this does nothing. Otherwise, it moves through the set and calls back to the update( ) member function of each Observer. Finally, it clears the changed flag so repeated calls to notifyObservers( ) won’t waste time.
At first it may appear that you can use an ordinary Observable object to manage the updates.
But this doesn’t work; to get an effect, you must inherit from Observable and somewhere in your derived-class code call setChanged( ). This is the member function that sets the
“changed” flag, which means that when you call notifyObservers( ) all of the observers will, in fact, get notified. Where you call setChanged( ) depends on the logic of your program.
Now we encounter a dilemma. An object that should notify its observers about things that
happen to it – events or changes in state – might have more than one such item of interest. For example, if you’re dealing with a graphical user interface (GUI) item – a button, say – the
Chapter 16: Design Patterns
924
items of interest might be the mouse clicked the button, the mouse moved over the button, and (for some reason) the button changed its color. So we’d like to be able to report all of these events to different observers, each of which is interested in a different type of event.
The problem is that we would normally reach for multiple inheritance in such a situation: “I’ll inherit from Observable to deal with mouse clicks, and I’ll … er … inherit from Observable to deal with mouse-overs, and, well, … hmm, that doesn’t work.”
The “interface” idiom
The “inner class” idiom
Here’s a situation where we do actually need to (in effect) upcast to more than one type, but in this case we need to provide several different implementations of the same base type. The solution is something I’ve lifted from Java, which takes C++’s nested class one step further.
Java has a built-in feature called inner classes, which look like C++’s nested classes, but they do two other things:
1. A Java inner class automatically has access to the private elements of the class it is nested within.
2. An object of a Java inner class automatically grabs the “this” to the outer class object it was created within. In Java, the “outer this” is implicitly dereferenced whenever you
name an element of the outer class.