![]() |
Development Lifecycle »
Design and Architecture »
Design Patterns
Intermediate
Chain of ResponsibilityBy T. Kulathu SarmaAn article showing the application of Chain of Responsibility in real world and software world. |
C++/CLI, Windows, .NET, Visual Studio, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
In general, patterns are not only applicable to software systems and not restricted only to software field. When we look things from a "pattern perspective", we can feel how patterns are integral part of our life and day-to-day activities. To quote some examples, doctors follow a specific pattern (or path) in diagnosing medical problems; architects use patterns in constructing buildings and chefs use patterns in cooking variants of a dish. Whatever the field is, the intent of a pattern is to provide solution to a recurring problem without having to reinvent the solution again and again. As a matter of fact, Christopher Alexander used patterns in the constructing of buildings and towns, which served as an inspiration for Erich Gamma et al to come up with the first authoritative work on Object Oriented Design Patterns.
It is a general feeling that Object Orientated concepts including design patterns are complex to understand. This is true at least with people who are new to object orientation and design patterns. Examples used to explain abstract concepts should be very clear for easy understanding; software examples are not always suitable for explaining certain abstract concepts. I strongly feel that any abstract concept can be better explained by relating them to concrete real world examples. Interestingly, we could relate software design patterns to activities that are integral part of our life, like our job, for example. In this article, I would like to introduce a design pattern called Chain of Responsibility and show how it can be related to the functioning of a real world Customer Support System. Throughout this article, I will explain the concept of Chain of Responsibility by relating them to real world and software world examples side by side.
Typically, a client request flows through a chain of people until it is successfully handled. The support model clearly defines the handling procedures and the escalation paths, in case the request needs to be forwarded. Functioning of the support team could be related to chain of objects co-operating to handle a request. Clients initiating a request with the first level support team will receive a response from one of the teams (not always from the first level support team) without having to know about the whole support model. Likewise, a client object can initiate a request to an handler object, which can provide a response or chain the request to the next handler object which can provide a response or in turn chain the request to the next handler object. Ultimately, the client getting the response need not know anything about the object handling the request. This object behavioral pattern is called, Chain of Responsibility. The main intent of this pattern is to de-couple the requestor (or the client object) from the actual handler (or the responding object) by giving an opportunity for more than one object to handle a given request. Both in the real world and object world, Chain of Responsibility allows handlers to be chained and pass the request along the chain.
CCmdTarget implementation details are beyond the scope of this article. MFC Internals by George Shepherd and Scot Wingo has a separate chapter on Message handling in MFC.
Windows is an event driven operating system. When a user interacts with a Windows application, it generates an event or a command message to the active window object. In traditional Windows programming, a windows procedure in the window object will have to handle the command. This leaves with just one handler for all the requests generated by user interaction. MFC framework has extended message-handling capabilities to other non-window objects like Documents (CDocument) and Application (CWinApp) objects. The main reason is to provide modularity and ensure separation of interests. For example, it is more appropriate for a document object to handle commands related to creating, loading and saving documents; view object to handle user interaction commands like editing and copying; while leaving application object to handle application level commands like help and exit. MFC refers to these objects as Command Targets, as they all can handle user commands. As there is more than one command target, MFC employs Chain of Responsibility pattern to define a protocol for handling or routing commands. This is very similar to our support system, where there is more than one team (command target) to handle client requests (commands) and our support model defines the protocol for handling and routing. I have used the terms requests and commands; handlers and command targets interchangeably in the following paragraphs.
Before getting into further details, we will see the three participants Handler, Concrete Handler and Client involved in Chain of Responsibility. Handler defines an interface for handling requests and optionally maintains a link to next handler in the chain; Concrete Handler is responsible for handling requests if it can or forwards the request to the next handler; Client initiates the request to a Concrete Handler in the chain.
In our support system, the overall support model (or Handler) defines the interface or protocol for handling requests; Concrete handlers are different support teams and Client is our customer calling the first level support. In MFC, CCmdTarget is the Handler and OnCmdMsg member function is the interface for handling requests. CFrameWnd, CView and CDocument are Concrete Handlers. Menus, Toolbars and Accelerator Keys are Clients initiating the command (request) to the main frame window.
In our support system, knowledge base and run book are used for handling the request and escalation paths define rules for routing the request to the next team when needed. In MFC, Command targets use OnCmdMsg member function to see whether they can handle a request or to route them to the next command target. The default implementation of OnCmdMsg in CCmdTarget uses the message map of the command target class to search for a handler function for each command it receives. If a match is found, then the handler is called. For command routing, command target calls the OnCmdMsg member function of the next command target in sequence. MFC uses a standard command routing table for determining the next command target. This table is present as part of Microsoft Visual C++ on line help and a copy of which is given at the end of this article for reference.
Client requests are recorded in our tracking system, which is used for routing requests between different teams or handlers. In MFC, requests are passed on to different command targets through the parameters of OnCmdMsg member function.
In our support system, the request recorded in the tracking system is closed when it is handled; similarly OnCmdMsg returns TRUE when the request is handled successfully or FALSE to pass the request to the next handler. Passing the request to the next handler or linking command targets in MFC is easy because of the object relationship that exists among MFC classes. Frames window knows about the active view, view knows about the document, document knows the document template etc. In MFC, command target routes the commands to the active child command target object (if present). If that object cannot handle the request, then command target itself tries to handle it, if not it routes the request to other command targets that it knows. This is very similar to the well-defined escalation paths in our support model.
OnCmdMsg method parameters in MFC) and the route for passing the request (escalation routes defined as part of the support model and command routing table in MFC) is clearly defined.
Added flexibility in assigning responsibilities to objects - Chain of Responsibility gives an added flexibility in distributing responsibilities among handler objects. In our support system, when the first level support team is fully occupied with customer requests, new requests are automatically routed to my team. Also, based on the volume of calls we have the flexibility of having additional support teams on a temporary or permanent basis without disrupting the chain. Similarly, MFC framework offers the flexibility of distributing commands to any of the command targets (statically or dynamically). For example, user command can be handled by active view (usually) or by frame window and this can be decided at compile time or runtime.
Receipt is not guaranteed - As there is no explicit receiver for the request, there is no guarantee it will be handled and it may fall off the end of the chain without ever being handled. However, this can be avoided by putting some controls in place during implementation. In our support system, the support manager will ensure that his team handles the request or escalates it to the next team in order to guarantee a timely response to the client. Similarly, MFC ensures that menu items, toolbar buttons and accelerator keys are disabled when there is no handler for a command.
|
When an object of this type receives a command . . . |
It gives itself and other command-target objects a chance to handle the command in this order: |
|
MDI frame window |
|
|
Document frame window |
|
|
View |
|
|
Document |
|
|
Dialog box |
|
| You must Sign In to use this message board. | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 10 Jul 2001 Editor: Chris Maunder |
Copyright 2001 by T. Kulathu Sarma Everything else Copyright © CodeProject, 1999-2009 Web20 | Advertise on the Code Project |