🎉 Hooray! After 3 years of work, I've finally released the ebook on design patterns! Check it out »

C#: Chain of Responsibility

Chain of Responsibility

Chain of Responsibility is behavioral design pattern that allows passing request along the chain of potential handlers until one of them handles request.

The pattern allows multiple objects to handle the request without coupling sender class to the concrete classes of the receivers. The chain can be composed dynamically at runtime with any handler that follows a standard handler interface.

Learn more about Chain of Responsibility

Application of the pattern in C#

Complexity:

Popularity:

Usage examples: The Chain of Responsibility pattern isn’t a frequent guest in a C# program since it’s only relevant when code operates with chains of objects.

Identification: The pattern is recognizable by behavioral methods of one objects indirectly call the same methods in other objects, while all the objects follow the common interface.

Example: Structure of the Pattern

This example illustrates the structure of the Chain of Responsibility design pattern. It focuses on answering these questions:

  • What classes does it consists of?
  • What roles do these classes play?
  • In what way the elements of the pattern are related?

Program.cs: Structural Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RefactoringGuru.DesignPatterns.ChainOfResponsibility.Structural
{
    interface Handler
    {
        Handler setNext(Handler handler);
		
        object Handle(object request);
    }

    abstract class AbstractHandler : Handler
    {
        private Handler nextHandler;

        public Handler setNext(Handler handler)
        {
            this.nextHandler = handler;
            return handler;
        }
		
        public virtual object Handle(object request)
        {
            if (this.nextHandler != null)
            {
                return this.nextHandler.Handle(request);
            }
            else
            {
                return null;
            }
        }
    }

    class MonkeyHandler : AbstractHandler
    {
        public override object Handle(object request)
        {
            if((request as string) == "Banana")
            {
                return "Monkey: I'll eat the " + request.ToString() + ".\n";
            }
            else
            {
                return base.Handle(request);
            }
        }
    }

    class SquirrelHandler : AbstractHandler
    {
        public override object Handle(object request)
        {
            if (request.ToString() == "Nut")
            {
                return "Squirrel: I'll eat the " + request.ToString() + ".\n";
            }
            else
            {
                return base.Handle(request);
            }
        }
    }

    class DogHandler : AbstractHandler
    {
        public override object Handle(object request)
        {
            if (request.ToString() == "MeatBall")
            {
                return "Dog: I'll eat the " + request.ToString() + ".\n";
            }
            else
            {
                return base.Handle(request);
            }
        }
    }

    class Client
    {
        public static void ClientCode(AbstractHandler handler)
        {
            foreach(var food in new List<string> { "Nut", "Banana", "Cup of coffee" })
            {
                Console.WriteLine("Client: Who wants a " + food + "?");

                var result = handler.Handle(food);

                if (result != null)
                {
                    Console.Write("   " + result);
                }
                else
                {
                    Console.WriteLine("   " + food + " was left untouched.");
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var monkey = new MonkeyHandler();
            var squirrel = new SquirrelHandler();
            var dog = new DogHandler();

            monkey.setNext(squirrel).setNext(dog);

            Console.WriteLine("Chain: Monkey > Squirerel > Dog\n");
            Client.ClientCode(monkey);
            Console.WriteLine();

            Console.WriteLine("Subchain: Squirrel > Dog\n");
            Client.ClientCode(squirrel);
        }
    }
}

Output.txt: Output

Chain: Monkey > Squirerel > Dog

Client: Who wants a Nut?
   Squirrel: I'll eat the Nut.Client: Who wants a Banana?
   Monkey: I'll eat the Banana
Client: Who wants a Cup of coffee?
   Cup of coffee was left untouched.

Subchain: Squirrel > Dog

Client: Who wants a Nut?
   Squirrel: I'll eat the Nut.Client: Who wants a Banana?
   Banana was left untouched.
Client: Who wants a Cup of coffee?
   Cup of coffee was left untouched.