Click here to Skip to main content
15,885,365 members
Articles / General Programming

Chain of Responsibility - ReExplained

Rate me:
Please Sign up or sign in to vote.
4.60/5 (5 votes)
1 Feb 2015CPOL10 min read 29.8K   49   12   2
Chain of Responsibility pattern is defined under behavioral design pattern by G.O.F and used to decouple the command with its processing object or handler.

Introduction

Here, We will know about the Chain of Responsibility pattern. This article will explain in details about

  • What it is ?
  • Why it is ?
  • How it is ?

Why this Article?  Well, I wanted to write an article which helps developers, not only to learn the implementation, but they also understand the core concept so that they can identify the actual scenario where they can fit this pattern. At the end of this article, I hope you will be able to describe yourself about the use and benefits of Chain of Responsibility.

 

Background

In your programming carrier, you might have faced the scenario, where you have multiple commands/requests and each command must be processed in some specific way. For that we create multiple handler objects whose job is to process those commands. We create those command handlers in a one to one mapping fashion, i.e. one handler for one command/request.


Generally, handlers are selected by the type of request, and this is done by a method which might handle the selection via if or switch statement, in some cases typeOf or type checking is also used. The problem is with if condition. This kind of common problem can be resolved easily by designing object hierarchy based on good object oriented design principal. One of the best applicable pattern is given by G.O.F as Chain of Responsibility.

 

What is it?

The Chain of Responsibility comes under behavioural pattern, as Its focus on the relationship among the objects. It concern about the delegation of responsibility among them and simplifies their intercommunication, thus helps to organise the control flow of object behaviour dynamically.

According to GOF,the formal definition is
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.

This pattern takes multiple command handler objects into the chain. Each command handler contains the reference of the next object in the chain, basically it creates a linklist of handlers. Now, the request is passed through this chain of objects, each object check the request to determine whether it can process the request or not. if current object can't process the request, it simply ignore the request and push the original request to next object in chain thus giving chance to another object to process the request. And, if current object is capable of processing the request then it start processing the request. Now once the processing is done, the current object can either exit the chain or pass the original request to the next handler in the queue/chain to process if it can.<o:p>

So, this pattern is all about providing a mechanism to allow a number of objects to attempt to handle a request, independently of any other object in the chain. Once the request is handled, it either exist on that point from the chain or travels along to the complete chain.<o:p>

 

Why is it?

As discussed earlier, generally handlers are selected through if-else or switch statements. The following problem resides if we use if-else / switch statement

  • Client must know about the command handler objects, i.e. you have to define handlers explicitly in your code. So, client and the handler object are tightly coupled.
  • As it is decided at design time, so, it is almost impossible, if multiple objects (determined at runtime) are candidates to handle a request without duplication of code.
  • System design in this way are less extensible and require a lot of impact analysis while doing code changes in maintenance as any changes in handler objects can easily break the client code.

As due to above complexity, the well-known common solution to this is to apply Chain of Responsibility pattern. The advantages are

  •  It decouples the request/command from it's handler objects. No direct explicit code is required to map these two.
  • More than one handlers can be made to process one command, and the client don't even need this information about such behaviour changes. So, such changes can be abstracted out from the client.
  • As all Handler objects are added to the chain, it can be associated/disassociated to the chain dynamically.

 

How is it?

In this pattern, one or more request handlers are associated to create a single chain. Each request handler object keeps a single reference to the next handler in the list. The request is then pushed to first handler in the list that inspect with some business logic, whether it can process it or not, and then it is pushed to the next handler in the list and so on.

It is applicable to those scenario where there are many different type of request exists and each request has specific processing requirements, and that processing logic is contained inside another object, and we want both the request and the handler object not to be tightly coupled (or not to use together explicitly in the code).

Let’s start with an scenario. I have an application (service) with talks to multiple devices running on multiple platform i.e. iPhone, android, windows etc. There is different apps for each mobile devices to which our application service communicate. For sake of simplicity, I will not concentrate on these mobile apps or application service. It is just a real scenario and I will use it like the base for the example in this article.

The application service allows the user to perform following operations on any of the devices:

  • Fetch/Search Contact List.
  • Fetch Messages
  • Fetch Memory Information.

Now, the above is just the 3 requirement, it will increase (may be more than 10-20) in future for sure. These are basically nothing but the request that our application service will send to the device app. The device app understand these requests and return the request with data as the response to the service, then the service will collect this response and start processing it. 

Flow of our example can be easily understood by the digram below.

Chain of Responsibility - Flow

I hope you will understand the theme of the example. Let’s make it.....

Note - To make this example simple and concise, I will keep my focus only on the pattern implementation, and it should not be seen as the actual implementation to be followed in production.

The following Enum is defined to hold symbolic constant for each requests that going to be handled by the application.

/// <summary>
/// Enum to define different types of Requests.
/// </summary>
internal enum RequestType
{
    Contact,
    Messages,
    Memory
}

First of all, an abstract class is defined which will be base class for all the concreate request classes which exists in our application. It is there only for the sake of abstraction, so that the communication of objects only depends on the abstraction not on the core implementing objects. It hold only those abstract behaviour whose concrete implementation must be provided by the derived classes. Here in this example, a single parameter-less contractor is defined to keep track of the type of request, i.e. whether it is of type Contact or Message or Memory.

        /// <summary>
        ///  Base class for all Requests.
        /// </summary>
        internal abstract class RequestBase
        {
            public readonly RequestType type ;
            protected RequestBase(RequestType type)
            {
                this.type = type;
            }
        } 

Now, Concreate request classes are defined which implements the RequestBase class. The concreate request classes will hold data specific to their own requirements. Basically, these classes are DTOs (data transfer objects), which hold only data, they generally do not know anything about the nature of data and how it will be used/processed. The processing algorithms/logics are contained in a separate class known as Request Handlers (in current context), we will see these handlers in action letter in this article.

The following code demonstrate all the three concreate implementation of Requests i.e. Contact RequestMessage Request and the Memory Request.

        #region Request Implementation

        /// <summary>
        /// Contact Request object to hold contact information.
        /// </summary>
        internal class ContactRequest : RequestBase
        {
            public int DeviceID { get; private set; }
            public string ContactName { get; private set; }

            public ContactRequest(int ID, string name) : base(RequestType.Contact)
            {
                this.DeviceID = ID;
                this.ContactName = name;
            }
        }

        /// <summary>
        /// Message Request object to hold Messages information.
        /// </summary>
        internal class MessagesRequest : RequestBase
        {
            
            public int DeviceID { get; private set; }
            public string Message { get; private set; }

            public MessagesRequest(int ID, string message)
                : base(RequestType.Messages)
            {
                this.DeviceID = ID;
                this.Message = message;
            }

        }

        /// <summary>
        /// Memory Request object to hold Memory information.
        /// </summary>
        internal class MemoryRequest : RequestBase
        {
            public int DeviceID { get; private set; }
            public int TotalMemory { get; private set; }
            public int MemoryLeft { get; private set; }

            public MemoryRequest(int ID, int totalMemory, int memoryLeft) : base(RequestType.Memory)
            {
                this.DeviceID = ID;
                this.TotalMemory = totalMemory;
                this.MemoryLeft = memoryLeft;
            }

        }

       
        #endRegion "End of Request Implementation"  

It's all. We have defined all the request classes that our application is to deal with. 

Now, Lets define another abstract class "RequestHandlerBase", which will be base class for all the request Handlers, as all handlers have some common behaviours to share. This base class will also serve the purpose of connecting link to create a queue/Lists, These links will contain the reference to another object in the list, in our example NextHandler is going to hold the reference.

/// <summary>
    /// Base class for all Request Handlers.
    /// </summary>
    internal abstract class RequestHandlerBase
    {
        private RequestHandlerBase NextHandler { get; set; }

        public void Execute(RequestBase request)
        {
            this.Process(request);
            PushNext(request);
        }

        protected abstract void Process(RequestBase request);

        public RequestHandlerBase SetNextHandler(RequestHandlerBase handler)
        {
            this.NextHandler = handler;
            return this.NextHandler;
        }

        private void PushNext(RequestBase request)
        {
            if (this.NextHandler != null)
                this.NextHandler.Execute(request);
        }
    }

Once the abstract class for the handler is defined, we are now ready to define concreate implementation for all the three request handlers, i.e. for contact, message and the memory requests. These request handlers knows how to process specific requests, they holds request specific business logics, and i.e. ContactRequestHandler object knows how to process the ContactRequest objects.

        #region Request Handler Implementation

        /// <summary>
        /// Contact Handler object to Handle Contact Request information.
        /// </summary>
        internal class ContactRequestHandler : RequestHandlerBase
        {
            protected override void Process(RequestBase request)
            {
                if (request.type == RequestType.Contact)
                {
                    var contact = (ContactRequest)request;
                    Console.WriteLine("Processing Contact Request. \n Device ID-> {0} - Contact Name ->{1}", contact.DeviceID, contact.ContactName);
                }
            }
        }

        /// <summary>
        /// Messages Handler object to Handle Message Request information.
        /// </summary>
        internal class MessagesRequestHandler : RequestHandlerBase
        {
            protected override void Process(RequestBase request)
            {
                if (request.type == RequestType.Messages)
                {
                    var message = (MessagesRequest)request;
                    Console.WriteLine("Processing Messages Request. \n Device ID-> {0} - Message ->{1}", message.DeviceID, message.Message);
                }
            }
        }

        /// <summary>
        /// Memory Handler object to Handle Memory Request information.
        /// </summary>
        internal class MemoryRequestHandler : RequestHandlerBase
        {
            protected override void Process(RequestBase request)
            {
                if (request.type == RequestType.Memory)
                {
                    var memory = (MemoryRequest)request;
                    Console.WriteLine("Processing Messages Request. \n Device ID-> {0} - Total Memory ->{1}  - Memory Left -> {2}", memory.DeviceID, memory.TotalMemory, memory.MemoryLeft);
                }
            }
        }
        
        #endregion "End of Request Handler Implementation"   

All set... Now let execute this. In the main section, we will be create and associate all the handlers to form a chain, and then different request are created, which need to be processed.

Note : In real scenario, the creation of the handlers may be delegated to the some builder objects, which can have the mechanism to dynamically create the lists of handlers based on certain rules. To keep this example simple and small, i have just created these objects in the main section itself.

        static void Main(string[] args)
        {
            // Create Request Handler Lists.
            var handler = new ContactRequestHandler();
            handler.SetNextHandler(new MessagesRequestHandler())
            .SetNextHandler(new MemoryRequestHandler());

            
            // Create Multiple requests.
            List<RequestBase> request = new List<RequestBase>();
            request.Add(new ContactRequest(2342244, "Nokia-X23"));
            request.Add(new MessagesRequest(2342244, "Hello Everyone ! how r u?"));
            request.Add(new MemoryRequest(2342244,2048,543));
            
            request.ForEach(x => {
                handler.Execute(x);
            });
        }

Once we execute, the following will be the output. 

Command Line result to show execution.

So, what is happening here is, we create list of different request, and each request is pushed to first hander object in the queue, now, that handler object checks the type of object it received to identify whether it should process this object or not. If it found it suitable for processing, then it starts processing, otherwise it simple ignore the request object and pass it to its next handler via the reference it holds. Thus the whole process works.

So, How it effects the Extensibility and Maintainability issues of the application ????

Now, in future, we called again to implement new requirement to our sample application. It is about Location. The client are very much concern about the Location feature. He wants the application should now also be capable of handling the Location information. So, let’s do it...........

As this is the new request, so add it to the RequestType Enum.

/// <summary>
/// Enum to define different types of Requests.
/// </summary>
internal enum RequestType
{
    Contact,
    Messages,
    Memory,
    Location
}

Now, define a LocationRequest class to represent the Location request to hold location specific data. Remember, it should be derived from the RequestBase class.

        /// <summary>
        /// Location Request object to hold Location information.
        /// </summary>
        internal class LocationRequest : RequestBase
        {
            public int DeviceID { get; private set; }
            public int Latitude  { get; private set; }
            public int Longitude  { get; private set; }

            public LocationRequest(int ID, int latitude, int longitude) : base(RequestType.Location)
            {
                this.DeviceID = ID;
                this.Latitude = latitude;
                this.Longitude = longitude;
            }

        }  

Now, define a handler for this newly defined request. Let’s name it LocationRequestHandler class. Make it derived from RequestHandlerBase class.

        /// <summary>
        /// Location Handler object to Handle Location Request information.
        /// </summary>
        internal class LocationRequestHandler : RequestHandlerBase
        {
            protected override void Process(RequestBase request)
            {
                if (request.type == RequestType.Location)
                {
                    var location = (LocationRequest)request;
                    Console.WriteLine("Processing Location Request. \n Device ID-> {0} -  Latitude->{1}  - Longitude -> {2}", location.DeviceID, location.Latitude, location.Longitude);
                }
            }
        }

Now, it’s all done.... We have to attach this LocationReqeustHandler to the Handler lists, as we have done the below code in the main section. 

        
        static void Main(string[] args)
        {
            // Create Request Handler Lists.
            var handler = new ContactRequestHandler();
            handler.SetNextHandler(new MessagesRequestHandler())
            .SetNextHandler(new MemoryRequestHandler())
            .SetNextHandler(new LocationRequestHandler());

            
            // Create Multiple requests.
            List<RequestBase> request = new List<RequestBase>();
            request.Add(new ContactRequest(2342244, "Nokia-X23"));
            request.Add(new MessagesRequest(2342244, "Hello Everyone ! how r u?"));
            request.Add(new MemoryRequest(2342244,2048,543));
            request.Add(new LocationRequest(2134324, 23434, 4645654));
            request.ForEach(x => {
                handler.Execute(x);
            });
        }   

After executing this, following result will be shown on the console.

Command result After execution -chain of Responsibility pattern

 

How simple and clear it is !!. We have successfully added a new feature to our example in the form of Request, without changing the existing code much, so this allow the system to be more extensible and maintainable without the risk of breaking the existing code.

 

Points of Interest

This pattern is recommended when either of the following scenarios occur in your application:

  • When there is multiple objects which can handle a specific request, i.e. you don't want to specify handlers explicitly in you code.
  • When the handler is to be decided dynamically, i.e. which candidate (handler objects) should be allowed to handle the request objects is determined at runtime
  • If a request not being handled, then is this acceptable scenario, i.e. no exception is thrown at any given point of time, it is simple ignored by the system.
  • When you want to decouple the request from its sender to its receiver or processor objects.

Remember.....

  • Many other Patterns like Mediator, Command and Observer also decouples the senders of the requests from its receiver’s objects, as like with Chain of Responsibility pattern. But they all achieve this in a different way. Like about shown, Chain of Responsibility uses the chain of handlers to pass the request through it.
  • Pattern can me mixed to achieve the best result, i.e. Command pattern can be used to wrap the request, and Chain of Responsibility can be decouple them from their handlers.

 

 
Keep Coding......

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I am Lalit Chandra. I have 6 year of working experience in .Net technologies. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce Portals and Data driven applications. I have designed and implemented flexible solutions which support frequent UI and functionality changes.

Comments and Discussions

 
QuestionMissing images. Pin
Pete O'Hanlon2-Feb-15 0:21
mvePete O'Hanlon2-Feb-15 0:21 
AnswerRe: Missing images. Pin
Nelek7-Feb-15 15:03
protectorNelek7-Feb-15 15:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.