Chain of responsibility

Chain of responsibility (COR)

This design pattern is again a very fundamental design pattern as there are numerous systems in this world which are incomplete without this pattern. While discussing the observer design pattern, we have discussed that Observer and COR are competing design patterns wherein in come cases Observer wins, while in some cases COR wins.

As discussed in the Observer design pattern

Lets say I am in classroom and I have a problem and I know one of the students in the class might have the answer to the same. So what are the two ways in which I can get my question answered

  • I can broadcast the question.. whoever knows the question will answer to the same and I might get the answer. This is the observer way of doing things.
  • I can pass the question to the first student in the class presuming that they are chained. If the first student knows the answer to the question, he can answer the same else he will pass the request to the next student … so the request propagates till either some student has an answer to it or the question gets unanswered . This is the chain of responsibility way of doing things.

Observer Design Pattern gives the best performance but with a possibility of network bandwidth congestion , while COR may give the worst performance but conserving network bandwidth.

As we performance is one of the very critical non functional characteristics expected by any system, it is highly unlikely that anyone will prefer a system designed using COR.

Then does it mean COR is never used?

The answer is although people will always prefer Observer over COR, but there are numerous situations in which Observer is just not technically possible, in that situation there is no option but to use COR.

Let me show you couple of real life examples where in designers would have preferred using Observer, but had to use COR as Observer was not practically possible.

Let me again take you to roaming communication model of mobile telephony. As shown in the figure when the caller calls a (mobile number) person who is not available in the local address space , the proxy intercepts the call and makes the caller believes that the target object is in the same address space. Now the proxy has to know the fully qualified address of the object (friend) which is on continuous move. This can be done in two ways either by using Observer or by using COR.

If Observer was supposed to be used, the proxy would have simply made a broadcast to all the home location registers (HLRs) or Naming Servers in this world saying whoever knows the fully qualified address of 9999999999 , give the fully qualified address of the same. In this case whoever knew the fully qualified address for this number, would have returned the address in the quickest possible time. No doubt this is the quickest possible solution , but ask yourself for the proxy to broadcast the request to all the HLRs/NSs in this world.. it has to know about all the HLRs and keep a reference to them. Now ask yourself can the proxy know about all the HLRs and its corresponding address when there are thousands of HLRs in this world (at least one per network).

Figure- Figure

So this is one of the cases wherein Observer would have been preferred but it is technically not possible to use Observer as it is not possible for the proxy to keep a reference to all the HLRs in the world because the sheer number of Naming Servers.

As observer is not possible , let us see if COR can help us solve this problem. In COR the proxy keeps a reference to the local HLR/NS which is chained to other HLRs in this world. So when proxy intercepts the call, the proxy asks the local HLR if it can resolve the address of 999999999, if the local HLR knows the address it can return else it passes it to next HLR in the chain … this keeps happening till either one of the HLR returns the address or the message cell phone is not reachable is played.

Figure- Figure

Chain of responsibility is mostly used to chain Naming Servers. Another classical example of the same can be seen in our internet architecture again explained in detail in the Proxy Server section of Proxy design pattern.

Think about the client browser has to get the IPAddress of the HTTPServer registered into the DNS Servers (Naming Server) against a URL. The ideal thing for the browser was to do a broadcast to all the DNS Servers in the world saying who ever knows the IP Address of HTTPserver against this URL please return it to us but for that to happen, the browser has to know about all the DNSServers and its address as well. Is it practically possible ? No … there are thousands of DNS servers in the world and its practically impossible to know about their exact number or to keep a reference to all of them . Again observer would have been preferred but was practically impossible hence COR is the only possible practical solution for the same.

Figure- Figure

Hence in the Internet architecture, the DNS Servers are chained to each other. When a browser wants the IP address of the HTTPServer , the browser communicates with the local DNSServer … if the local DNS Server can resolve the IP Address , it can return the same else it passes the request to the next DNS Server in the chain …and the request keeps propagating till some one is able to resolve the IP address.

Figure- Figure

This is again a case wherein observer would have been preferred, but COR is used as implementing Observer was practically impossible or difficult.

Chain of responsibility also has applications within our programming languages as well. One of the classical applications of COR in our programming languages is Exception Handling.

In most of the programming languages, exception handling is designed in a way … wherein if there is an exception occurring at any point in one of the invoked methods. First that immediate method is given a chance to handle the exception, if the immediate method can handle the same its OK otherwise the preceding thread will be given a chance to handle the exception .. this continues to move backwards wherein either one of the preceding threads can handle the exception else the exception gets unhandled.

Figure- Figure

Now ask yourself why is COR preferred for Exception handling as compared to the Observer. Look into the next figure , lets say that the exception occurs in the method executing in thread T4, ideally it would have been the best possible option if T4 was able to broadcast the exceptions to all of the preceding threads asking one of them to handle the exception. But think about it , for thread T4 to do a broadcast it has to know about all the previous thread objects and its reference and is it possible for T4 to know about all the previous thread objects. Can we predict the time and place at which exception will occur? So how do we know how many previous thread objects where existing before the thread of execution where the exception would have occurred ? …Many times I come across participants who say that we can maintain a collection which will hold all the thread objects so that whenever there is an exception we already have the references of the previous thread objects and hence we can broadcast… But what if the exception did not occur at all… in that case maintaining the thread objects in the collection will all go as a wasteful resource.

Figure- Figure

So ideally observer would have been preferred but not practically possible also response time/performance is not very critical hence COR seems to be better design decision.

The figure below shows the class diagram of the COR . As you can see every object (ConcreteHandler) in the chain that is willing to handle requests should implement the Handler interface which has a method called as handleRequest(). This ensures all the ConcreteHandlers will also override the handleRequest() method. The chaining of handlers is represented by the link between ConcreteHandler and the Handler Interface.

Figure- Figure

So we can see that from an implementation point of view, COR is a very simple design pattern but conceptually it is one of the very important and fundamental design patterns without which a lot of systems cease to exist.

Hemant Jha
Founder - VPlanSolutions
Researcher, Trainer