Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Chain Of Responsibility Pattern

0.00/5 (No votes)
20 Oct 2013 1  
The chain of responsibility pattern is a way of communication between objects. As it’s name indicate a chain of handlers is built  and every handler

This articles was originally at wiki.asp.net but has now been given a new home on CodeProject. Editing rights for this article has been set at Bronze or above, so please go in and edit and update this article to keep it fresh and relevant.

Introduction

The chain of responsibility pattern is a way of communication between objects.
As it’s name indicate a chain of handlers is built and every handler in the chain is responsible to handle the passing request or deliver it to the next handler in the chain. In the end of the process the request is handled with a default or exceptional behaviour.
The pattern helps to reduce coupling by freeing the object from knowing which handler will handle the request in the end. 

Use Cases for the Chain of Responsibility Pattern

You should use the pattern in the following cases:

  • You have more than one object that may handle a request.
  • You have a scenario that you need to pass a request to one of several objects without specifying the receiver.
  • You have handlers of a request that should be specified dynamically.

UML Diagram

Example in C#

    #region Abstract Handler Class

    public abstract class Handler
    {
        #region Properties
        /// <summary>
        /// The request limit that the current handler can process
        /// </summary>
        public int RequestLimit { get; private set; }

        /// <summary>
        /// The next handler in the chain
        /// </summary>
        public Handler NextHandler { get; private set; }
        #endregion

        #region Methods
        public abstract void HandleRequest(int request);
        #endregion

        #region Ctor
        public Handler(Handler handler, int requestLimit)
        {
            NextHandler = handler;
            RequestLimit = requestLimit;
        }
        #endregion
    }

    #endregion

    #region Concrete Handlers

    public class Worker : Handler
    {
        #region Ctor
        /// <summary>
        /// Construct a new worker object with the given handler
        /// </summary>
        /// <param name="handler">The given handler</param>
        public Worker(Handler handler)
            : base(handler, 10000)
        {
        }
        #endregion

        #region Methods
        public override void HandleRequest(int request)
        {
            if (request < RequestLimit)
            {
                Console.WriteLine("{0} handled a {1} request", GetType().Name, request);
            }
            else
            {
                if (NextHandler != null)
                {
                    NextHandler.HandleRequest(request);
                }
            }
        }
        #endregion
    }

    public class Manager : Handler
    {
        #region Ctor
        /// <summary>
        /// Construct a new manager object with the given handler
        /// </summary>
        /// <param name="handler">The given handler</param>
        public Manager(Handler handler)
            : base(handler, 20000)
        {
        }
        #endregion

        #region Methods
        public override void HandleRequest(int request)
        {
            if (request < RequestLimit)
            {
                Console.WriteLine("{0} handled a {1} request", GetType().Name, request);
            }
            else
            {
                if (NextHandler != null)
                {
                    NextHandler.HandleRequest(request);
                }
            }
        }
        #endregion
    }

    public class SeniorManager : Handler
    {
        #region Ctor
        /// <summary>
        /// Construct a new senior manager object with the given handler
        /// </summary>
        /// <param name="handler">The given handler</param>
        public SeniorManager(Handler handler)
            : base(handler, 50000)
        {
        }
        #endregion

        #region Methods
        public override void HandleRequest(int request)
        {
            if (request < RequestLimit)
            {
                Console.WriteLine("{0} handled a {1} request", GetType().Name, request);
            }
            else
            {
                if (NextHandler != null)
                {
                    NextHandler.HandleRequest(request);
                }
            }
        }
        #endregion
    }

    #endregion

The example is simple.
I have three types of workers: worker, manager and a senior manager. Every worker type can handle request that are lower than the request limit they have.
Whenever a request that is bigger than the request limit arrives the worker type deliver the request to the next handler in the chain until there is no one who can handle the request.

The following example shows a use case of the example classes:

    class Program 
    { 
        static void Main(string[] args)
        {
            // Setup Chain of Responsibility
            SeniorManager seniorManager = new SeniorManager(null);
            Manager manager = new Manager(seniorManager);
            Worker worker = new Worker(manager);

            // Run requests along the chain
            worker.HandleRequest(5000);
            worker.HandleRequest(15000);
            worker.HandleRequest(35000);

            Console.WriteLine();

            manager.HandleRequest(5000);
            manager.HandleRequest(15000);
            manager.HandleRequest(35000);

            Console.WriteLine();

            seniorManager.HandleRequest(5000);
            seniorManager.HandleRequest(15000);
            seniorManager.HandleRequest(35000);

            // Wait for user
            Console.Read();
        }
    }

Summary

To sum up, the chain of responsibility pattern isn’t commonly used. Even so it’s very helpful if you want to send a request along a chain of objects that may or may not handle the request.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here