EventHandler Class
Listing 2 contains a constructor that sets the member properties to null default values. The member function HasEventSupport() indicates whether the object of this class provides event support. The chain of responsibility pattern allows objects to either provide support or to pass the event along to the _successor object. If the object of this class wants to provide a specific event handler, it calls SetHandler(EventHandler*, Event). The last member function is HandleEvent(), which is used to implement the event handler. Two member properties are provided in the EventHandler base class: _successor and _event. The _successor is a pointer to the next handler in the chain or responsibility; that is, if I don’t handle the event, I pass it on the _successor. The event in question is stored in the _event variable.
Let’s now see how this base class is used to provide the chain of responsibility.
Connection Subclass of EventHandler
Given that we’re using a devolved model for event management, we now define a Connection class in Listing 3. Remember the LSP (LSP123) in Figure 1? Well, this is an EventHandler subclass to represent such logical connections.
Listing 3 Connection: A Derived Class of EventHandler
class Connection : public EventHandler { public: Connection(Event t) : EventHandler(0, t) { } virtual void HandleEvent(); }; void Connection ::HandleEvent() { } class Path : public Connection { public: Path::Path(Connection* w, Event t) : Connection(0) { cout << "In the Path constructor\n"; SetHandler(w, t); }
Connection is a generic subclass of EventHandler. I say generic because Connection can be used (via inheritance) to model any type of logical network connection, such as LSPs, IP tunnels, and so on. Just think of it as a placeholder for more specialized subclasses in the same way as "Human" is a generic placeholder type for "Male" and "Female".
Listing 3 defines another class called Path derived from Connection. Path is a means of storing a route for an LSP (such as LSP123, which follows the route R2-R3-R4-R5 in Figure 1). Listing 4 illustrates the last class of interest to us: the Lsp class derived from Connection.
Listing 4 Lsp Class: A Specific Connection Subclass
class Lsp : public Connection { public: Lsp::Lsp(char* lspID, Connection* w, Event t) : Connection(0) { lspName = lspID; SetHandler(w, t); } void HandleEvent() { if (HasEventSupport()) { cout << "\nAt last, here’s some LSP Event support:\n"; cout << "We need more bandwidth on " << lspName << "\n\n"; } else EventHandler::HandleEvent(); } private: char* lspName; };
The Lsp class acquires (via inheritance) all the capabilities of EventHandler as well as adding a few wrinkles of its own. As you can see, Lsp implements the HandleEvent() member function. This member function is defined as virtual in the EventHandler base class, so subclasses are free to define it as required. In the case of the Lsp class, the event support provided is to print out an informative message.
Now let’s put it all together and build the chain of responsibility, as illustrated in Listing 5 (repeated from Listing 1).
Listing 5 The Chain of Responsibility
Connection* connection = new Connection(No_Event_Support); Lsp* lsp = new Lsp("LSP_IPTV0001", connection, LINK_1A_CONGESTION); Path* path = new Path(lsp, No_Event_Support); path->HandleEvent();
At the top of the chain is a Connection* object. The next level in the chain is an Lsp* object. Finally, at the bottom of the chain is a Path* object. To start the event processing, we simply call path->HandleEvent().
This simulates our link failure from Figure 1. Listing 6 illustrates part of the program output (excluding initialization in the constructors).
Listing 6 Program Output
No support from Path - Sorry! Calling the base class event handler HandleEvent () calling into successor At last, here’s some LSP Event support: We need a new path for LSP123
The first line of Listing 6 shows us that the path object can’t offer any help because the Path class implements a very thin HandleEvent() method. So because the path object can’t process the event, it calls the base class HandleEvent() method, which then results in a call to the Lsp HandleEvent() method. As the second-to-last line in Listing 6 illustrates, we finally get some help from this object in the form of a message indicating that we need a new path for the LSP (LSP123) that traverses the (now) broken link in Figure 1.
That’s it! That’s our chain of responsibility passing the event around like a hot potato until an appropriate handler is found. It’s a little like someone in a crowded room saying, "Is anyone here a doctor?"