CHAPTER 20

image

Chain of Responsibility Patterns

GoF Definition: Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Concept

Here we process a series of objects one by one (i.e., in a sequential manner). A source will initiate this processing. With this pattern, we constitute a chain where each of the processing objects can have some logic to handle a particular type of command object. After one’s processing is done, if anything is still pending, it can be forwarded to the next object in the chain. We can add new objects anytime at the end of a chain.

Real-Life Example

In an organization, there are some customer care executives who handle feedback/issues from customers and forward those customer issues/escalations to the appropriate department in the organization. Not all departments will start fixing an issue. The department that seems to be responsible will take a look first, and if the department staff believe that the issue should be forwarded to another department, he/she will do that.

Computer World Example

Consider an application which is handling e-mail and faxes. As usual, we need to take care of the issues reported in each of these communications. We need to introduce two error handlers—EmailErrorHandler and FaxErrorHandler. EmailErrorHandler will handle e-mail errors only and is not responsible for fax errors. In the same manner, FaxErrorHandler will handle fax errors and does not care about e-mail errors.

Then we can make a chain as follows: whenever our main application finds an error, it will just raise this and forward the error with the hope that one of those handlers will handle it. The request will first come to FaxErrorhandler—if it finds that it is a fax issue, it’ll handle the request; otherwise, it will forward the issue to EmailErrorHandler.

Note that here our chain ends with EmailErrorHandler. But if we need to handle another type of issue (e.g., Authentication), we can make an AuthenticationErrorHandler and put it after EmailErrorHandler. So, now, whenever the issue cannot be fixed by EmailErrorHandler, the issue can be forwarded to AuthenticationErrorHandler and the chain will end there.

Thus, the bottom line is as follows: the chain will end if the issue is being processed by some handler or there are no more handlers to process it (i.e., we have reached the end of the chain).

Illustration

In this example, we are processing both normal and high-priority issues from e-mail and fax communications.

UML Class Diagram

9781484218013_unFig20-01.jpg

Package Explorer view

High-level structure of the parts of the program is as follows:

9781484218013_unFig20-02.jpg

Implementation

package chainofresponsibility.pattern.demo;
enum MessagePriority
{
        Normal,
        High
}
class Message
{
        public String Text;
        public MessagePriority Priority;
        public Message(String msg, MessagePriority p)
        {
                Text = msg;
                this.Priority = p;
        }
}

interface IReceiver
{
        Boolean ProcessMessage(Message msg);
}
Class IssueRaiser
{
        public IReceiver setFirstReceiver;
        public IssueRaiser(IReceiver firstReceiver)
        {
                this.setFirstReceiver = firstReceiver;
        }
        public void RaiseMessage(Message msg)
        {
                if (setFirstReceiver != null)
                        setFirstReceiver.ProcessMessage(msg);
        }
}
class FaxErrorHandler implements IReceiver
{
        private IReceiver _nextReceiver;
        public FaxErrorHandler(IReceiver nextReceiver)
        {
                _nextReceiver = nextReceiver;
        }
        public Boolean ProcessMessage(Message msg)
        {
                if (msg.Text.contains("Fax"))
                {
                        System.out.println("FaxErrorHandler processed "+  msg.Priority+ "priority issue: "+ msg.Text);
                        return true;
                }
                else
                {
                        if (_nextReceiver != null)
                                _nextReceiver.ProcessMessage(msg);
                }
                return false;
        }
}
class EmailErrorHandler implements IReceiver
{
        private IReceiver _nextReceiver;
        public EmailErrorHandler(IReceiver nextReceiver)
        {
                _nextReceiver = nextReceiver;
        }
        public Boolean ProcessMessage(Message msg)
        {
                if (msg.Text.contains("Email"))
                {
                        System.out.println("EmailErrorHandler processed "+ msg.Priority+ "priority issue: "+ msg.Text);
                        return true;
                }
                else
                {
                        if (_nextReceiver != null)
                                _nextReceiver.ProcessMessage(msg);
                }
                return false;
        }
}
class ChainOfResponsibilityPatternEx
{
        public static void main(String[] args)
        {
                System.out.println("***Chain of Responsibility Pattern Demo*** ");
                //Making the chain first: IssueRaiser->FaxErrorhandler->EmailErrorHandler
                IReceiver faxHandler, emailHandler;
                //end of chain
                emailHandler = new EmailErrorHandler(null);
                //fax handler is before email
                faxHandler = new FaxErrorHandler(emailHandler);

                //starting point: raiser will raise issues and set the first handler
                IssueRaiser raiser = new IssueRaiser (faxHandler);

                Message m1 = new Message("Fax is reaching late to the destination", MessagePriority.Normal);
                Message m2 = new Message("Email is not going", MessagePriority.High);
                Message m3 = new Message("In Email, BCC field is disabled occasionally", MessagePriority.Normal);
                Message m4 = new Message("Fax is not reaching destination", MessagePriority.High);

                raiser.RaiseMessage(m1);
                raiser.RaiseMessage(m2);
                raiser.RaiseMessage(m3);
                raiser.RaiseMessage(m4);

        }
}

Output

9781484218013_unFig20-03.jpg

Note

  1. This pattern is used when we issue a request without specifying the receiver. We expect any of our receivers to handle that request.
  2. There may be situation in which more than one receiver can handle the request but the receivers do not know the priority. However, we want to handle the request by the receiver based on the priority. This pattern can help us to design such a scenario.
  3. We may need to have the capability to specify objects (that can handle a request) in runtime.
  4. We can either define a new link or use an existing link when we need to implement a successor chain.
  5. Sometimes we can try to implement an automatic mechanism for forwarding a request. The advantage is that we can avoid implementing a specific forwarding mechanism from one point to another point in our chain. Smalltalk’s doesnotUnderstand is a typical example in this context.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset