Professional C__ - Marc Gregoire [492]
Code snippet from Decorator\Decorator.cpp
The output will be as follows:
A party? For me? Thanks!
A party? For me? Thanks!
There is an interesting side effect of this implementation that just happens to work correctly for HTML. If you applied the same style twice in a row, the effect would only occur once:
cout << BoldParagraph(BoldParagraph(p)).getHTML() << endl;
The result of this line is:
A party? For me? Thanks!
If you can see the reason why, you’ve mastered C++! What’s happening here is that instead of using the BoldParagraph constructor that takes a const Paragraph reference, the compiler is using the built-in copy constructor for BoldParagraph! In HTML, that’s fine — there’s no such thing as double-bold. However, other decorators built using a similar framework may need to implement the copy constructor to properly set the reference.
THE CHAIN OF RESPONSIBILITY PATTERN
A chain of responsibility is used when you want each class in an object-oriented hierarchy to get a crack at performing a particular action. The technique generally employs polymorphism so that the most specific class gets called first and can either handle the call or pass it up to its parent. The parent then makes the same decision — it can handle the call or pass it up to its parent. A chain of responsibility does not necessarily have to follow a class hierarchy, but it typically does.
Chains of responsibility are perhaps most commonly used for event handling. Many modern applications, particularly those with graphical user interfaces, are designed as a series of events and responses. For example, when a user clicks on the File menu and selects Open, an open event has occurred. When the user moves the mouse over the drawable area of a paint program, mouse move events are generated continuously. If the user presses down a button on the mouse, a mouse down event for that button-press is generated. The program will then start paying attention to the mouse move events, allowing the user to “draw” some object, and continue doing this until the mouse up event occurs. Each operating system has its own way of naming and using these events, but the overall idea is the same: When an event occurs, it is somehow communicated to the program, which takes appropriate action.
As you know, C++ does not have any built-in facilities for graphical programming. It also has no notion of events, event transmission, or event handling. A chain of responsibility is a reasonable approach to event handling because in an object-oriented hierarchy, the processing of events often maps to the class/subclass structure.
Example: Event Handling
Consider a drawing program, which has a hierarchy of Shape classes, as in Figure 29-8.
FIGURE 29-8
The leaf nodes handle certain events. For example, Square or Circle can receive mouse down events that will select the chosen shape. The parent class handles events that have the same effect regardless of the particular shape. For example, a delete event is handled the same way, regardless of the type of shape being deleted. The ideal algorithm for handling a particular event is to start at the leaf nodes and walk up the hierarchy until the message is handled. In other words, if a mouse down event occurs on a Square object, first the Square will get a chance to handle the event. If it doesn’t recognize the event, the Shape class gets a chance. This approach is an example of a chain of responsibility because each subclass may pass the message up to the next class in the chain.
Implementation of a Chain of Responsibility
The code for a chained messaging approach will vary based on how the operating system handles events, but it tends to resemble the following code, which uses integers to represent types of events:
void Square::handleMessage(int inMessage)
{
switch (inMessage) {
case kMessageMouseDown:
handleMouseDown();
break;
case kMessageInvert:
handleInvert();
break;
default:
// Message not recognized--chain to superclass
Shape::handleMessage(inMessage);
}
}
void Shape::handleMessage(int