Chain of Responsibility Pattern

This type of pattern falls in the behavioural design patterns category. It is a design pattern where a sender sends a request to a chain of objects, the sender does not know which object in the chain will handle the request and the objects in the chain decide themselves who to honour the request. Every object in the chain has the responsibility to decide the request, if they cannot serve the request then it may forward it to the next node in the chain, hence the chain of responsibility. This pattern of delegation is often encountered in the real world where there’s one interface for the client (sender) to go through. A good example is a loan application where your loan request may be channeled and handled by one particular department. Another concrete example is an expenses/requisitions request approval in a company setup where each head of department has the approval authority and depending on the value of the expense/requisition, his authority may approve the request or forward it to the next authority in the chain. Other good examples which come to mind are Coin sorting machine, rank poker hands and ATM money dispensers.

Now let’s see how we might implement the Chain of Responsibility with some code example. Let’s use expenses/requisitions request approval explained above. We’ll start by defining our Requisition interface, which simply has the Amount property (the requisition value)


public interface IRequisition
{
    Decimal Amount { get; }
}

Its concrete implementation is as follows


public class Requisition : IRequisition
{
    public Requisition(Decimal amount) {
        Amount = amount;
    }

    public Decimal Amount { get; private set; }
}

For the requisition approval authority, an employee who has the responsibility to approve a requisition

public interface IRequisitionApprover
{
    ApprovalResponse ApproveRequisition(IRequisition requisition);
}

public enum ApprovalResponse
{
    Denied,
    Approved,
    BeyondApprovalLimit,
}

The implementation follows:

public class Employee : IRequisitionApprover
{
    public Employee(string name, Decimal approvalLimit)
	{
		Name = name;
		this.approvalLimit = approvalLimit;
	}

	public string Name { get; private set; }

	public ApprovalResponse ApproveExpense(IRequisition requisition)
	{
		return (requisition.Amount > _approvalLimit)
			? ApprovalResponse.BeyondApprovalLimit: ApprovalResponse.Approved;
	}

	private readonly Decimal approvalLimit;
}

Next we define the RequisitionHandler class which represents a single link in the chain of responsibility

public interface IRequisitionHandler
{
	ApprovalResponse Approve(IRequisition requisition);
	void RegisterNext(IRequisitionHandler next);
}

public class RequisitionHandler: IRequisitionHandler
{
	public ExpenseHandler(IRequisitionApprover requisitionApprover)
	{
		approver = requisitionApprover;
		next = EndOfChainExpenseHandler.Instance;
	}

	public ApprovalResponse Approve(IRequisition requisition)
	{
		ApprovalResponse response = approver.ApproveExpense(requisition);
		if(response == ApprovalResponse.BeyondApprovalLimit)
		{
			return next.Approve(requisition);
		}

		return response;
	}

	// Register the next link in the chain i.e. if the current handler
	// cannot approve the requisition request then forward it to the next node in the chain
	public void RegisterNext(IRequisitionHandler next)
	{
		this.next = next;
	}

	private readonly IRequisitionApprover approver;
	private IRequisitionHandler next;
}

We need to define an end of chain handler that handles requisition values beyond the approval limit of the last member of the chain, this class exposes a singleton instance

class EndOfChainRequisitionHandler : IRequisitionHandler
{
    private EndOfChainRequisitionHandler() { }
    public static EndOfChainRequisitionHandler Instance
	{
		get { return instance; }
	}

	public ApprovalResponse Approve(IExpenseReport expenseReport)
	{
		// return denied, always and only since we've made it to this point and nobody has
		// approved the requisition and we shouldn't approve it here
		return ApprovalResponse.Denied;
	}

	public void RegisterNext(IExpenseHandler next)
	{
		throw new InvalidOperationException("End of chain handler must be the end of the chain!");
	}

	private static readonly EndOfChainRequisitionHandler instance = new EndOfChainRequisitionHandler();
}

For the application logic

class Approval
{
	static void Main()
	{
		RequisitionHandler josh = new RequisitionHandler(new Employee("Josh SeniorDeveloper", Decimal.Zero));
		RequisitionHandler scott = new RequisitionHandler(new Employee("Scott LineManager", new Decimal(1000)));
		RequisitionHandler rudo = new RequisitionHandler(new Employee("Rudo ViceChair", new Decimal(5000)));
		RequisitionHandler chris = new RequisitionHandler(new Employee("Chris Chairman", new Decimal(20000)));

		josh.RegisterNext(scott);
		scott.RegisterNext(rudo);
		rudo.RegisterNext(chris);

		Decimal requisitionAmount;
		if (ConsoleInput.TryReadDecimal("Expense requisition amount:", out requisitionAmount))
		{
			// Create a requisition object
			IRequisition requisition = new Requisition(requisitionAmount);

			// Got to the head of the chain Josh and ask if he can approve this requisition
			ApprovalResponse response = josh.Approve(requisition);

			Console.WriteLine("The request was {0}.", response);

			Console.ReadKey();
		}
	}
}

Helper class

public static class ConsoleInput
{
	public static bool TryReadDecimal(string prompt, out Decimal value)
	{
		value = default(Decimal);

		while (true)
		{
			Console.WriteLine(prompt);
			string input = Console.ReadLine();
			if (string.IsNullOrEmpty(input))
			{
				return false;
			}

			try
			{
				value = Convert.ToDecimal(input);
				return true;
			}
			catch (FormatException)
			{
				Console.WriteLine("The input is not a valid decimal.");
			}
			catch (OverflowException)
			{
				Console.WriteLine("The input is not a valid decimal.");
			}
		}
	}
}