f.close(); // It's already closed; no change
f.openNotifier.deleteObservers();
f.open();
f.close();
} ///:~
The events of interest are that a Flower can open or close. Because of the use of the inner class idiom, both these events can be separately observable phenomena. The OpenNotifier and CloseNotifier classes both derive from Observable, so they have access to setChanged( ) and can be handed to anything that needs an Observable. You’ll notice that, contrary to InnerClassIdiom.cpp, the Observable descendants are public. This is because some of their member functions must be available to the client programmer. There’s nothing that says that an inner class must be private; in InnerClassIdiom.cpp we were simply following the design guideline "make things as private as possible." You could make the classes private and expose the appropriate member functions by proxy in Flower, but it wouldn’t gain much.
The inner class idiom also comes in handy to define more than one kind of Observer, in Bee and Hummingbird, since both those classes may want to independently observe Flower openings and closings. Notice how the inner class idiom provides something that has most of the benefits of inheritance (the ability to access the private data in the outer class, for example).
In main( ), you can see one of the primary benefits of the Observer pattern: the ability to change behavior at runtime by dynamically registering and unregistering Observers with Observables.
If you study the previous code, you’ll see that OpenNotifier and CloseNotifier use the basic Observable interface. This means that you could derive from other completely different Observer classes; the only connection the Observers have with Flowers is the Observer interface.
Multiple dispatching
When dealing with multiple types that are interacting, a program can get particularly messy. For example, consider a system that parses and executes mathematical expressions. You want to be able to say Number + Number, Number * Number, and so on, where Number is the base class for a family of numerical objects. But when you say a + b, and you don’t know the exact type of either a or b, how can you get them to interact properly?
The answer starts with something you probably don’t think about: C++ performs only single dispatching. That is, if you are performing an operation on more than one object whose type is unknown, C++ can invoke the dynamic binding mechanism on only one of those types. This doesn’t solve the problem, so you end up detecting some types manually and effectively producing your own dynamic binding behavior.
The solution is called
Here’s an example of multiple dispatching:
//: C10:PaperScissorsRock.cpp
// Demonstration of multiple dispatching
#include
#include
#include
#include
#include
#include
#include "../purge.h"
using namespace std;
class Paper;
class Scissors;
class Rock;
enum Outcome { win, lose, draw };
ostream&
operator<<(ostream& os, const Outcome out) {
switch(out) {
default:
case win: return os << "win";
case lose: return os << "lose";
case draw: return os << "draw";
}
}
class Item {
public:
virtual Outcome compete(const Item*) = 0;
virtual Outcome eval(const Paper*) const = 0;
virtual Outcome eval(const Scissors*) const= 0;
virtual Outcome eval(const Rock*) const = 0;
virtual ostream& print(ostream& os) const = 0;
virtual ~Item() {}
friend ostream&
operator<<(ostream& os, const Item* it) {
return it->print(os);
}
};
class Paper : public Item {
public:
Outcome compete(const Item* it) {
return it->eval(this);
}
Outcome eval(const Paper*) const {
return draw;
}
Outcome eval(const Scissors*) const {
return win;
}
Outcome eval(const Rock*) const {
return lose;
}
ostream& print(ostream& os) const {