How To Implement Chain of Responsibility Design Pattern in C#

What is Chain of Responsibility Design pattern?

The chain of responsibility pattern is a behavioral software design pattern that implements the Requestor/Handler architecture using a chain of handlers. Each handler can do its own job or pass the request to another handler in the chain. In this way, it’s possible to build complex logic without creating complex classes.

Chain of Responsibility pattern is a flow control pattern, which is used to process the requests based on their type. It is an alternative to if-else or switch statements.

When and How to Use Chain Of Responsibility pattern?

You want to delegate some work to other objects without knowing their exact class names at compile time.

There are many use cases for this pattern, but here are some examples:

  • Expense approval system. In this case, approval can be done at different levels (e.g. Director, President or Vice-president)
  • Logging system. The log can be written in different formats (e.g. XML / JSON), and multiple handlers may be configured to write to the same format
  • Security system. The security rule may differ depending on who is accessing the system (an administrator vs a regular user)

In this article I will implement the Expense Approval System

Approver.cs

	/// <summary>
	/// The 'Handler' abstract class
	/// </summary>
	abstract class Approver
	{
		protected Approver successor;
		public void SetSuccessor(Approver successor)
		{
			this.successor = successor;
		}
		public abstract void ProcessRequest(Expense loan);
	}

Director.cs

	/// <summary>
	/// The 'ConcreteHandler' class
	/// </summary>
	class Director : Approver
	{
		public override void ProcessRequest(Expense loan)
		{
			if (loan.Amount < 10000.0)
			{
				Console.WriteLine("{0} approved request# {1}",
				  this.GetType().Name, loan.Amount);
			}
			else if (successor != null)
			{
				successor.ProcessRequest(loan);
			}
		}
	}

VicePresident.cs

	/// <summary>
	/// The 'ConcreteHandler' class
	/// </summary>
	class VicePresident : Approver
	{
		public override void ProcessRequest(Expense loan)
		{
			if (loan.Amount < 25000.0)
			{
				Console.WriteLine("{0} approved request# {1}",
				  this.GetType().Name, loan.Amount);
			}
			else if (successor != null)
			{
				successor.ProcessRequest(loan);
			}
		}
	}

President.cs

	/// <summary>
	/// The 'ConcreteHandler' class
	/// </summary>
	class President : Approver
	{
		public override void ProcessRequest(Expense
			loan)
		{
			if (loan.Amount < 100000.0)
			{
				Console.WriteLine("{0} approved request# {1}",
				this.GetType().Name, loan.Amount);
			}
			else
			{
				Console.WriteLine(
				"Request# {0} requires an executive meeting!",
				loan.Amount);
			}
		}
	}

Expense.cs

	/// <summary>
	/// Class holding request details
	/// </summary>

	class Expense
	{
		private double _amount;
		private string _purpose;

		// Constructor
		public Expense(double amount, string purpose)
		{
			this._amount = amount;
			this._purpose = purpose;
		}

		// Gets or sets amount
		public double Amount
		{
			get { return _amount; }
			set { _amount = value; }
		}

		// Gets or sets purpose
		public string Purpose
		{
			get { return _purpose; }
			set { _purpose = value; }
		}
	}

}

How to use the pattern

Program.cs

using System;
namespace ChainOfResponsibility
{
	class Program
	{
		static void Main(string[] args)
		{
			// Setup Chain of Responsibility
			Director director = new Director();
			VicePresident vicePresident = new VicePresident();
			President president = new President();

			director.SetSuccessor(vicePresident);
			vicePresident.SetSuccessor(president);

			// Generate and process loan requests
			Expense l1 = new Expense(2034.34, "Personal");
			director.ProcessRequest(l1);

			Expense l2 = new Expense(32590.10, "Personal");
			director.ProcessRequest(l2);

			Expense l3 = new Expense(18902.74, "Business");
			director.ProcessRequest(l3);

			Expense l4 = new Expense(123098.50, "Business");
			director.ProcessRequest(l4);


		}
	}

Chain Of Responsebility

Let’s understand the above code - the client calls the first handler of the chain, which decides that it doesn’t want to handle the request. It then returns the request to its caller (the client) by calling its SetSuccessor method. The client then calls the next handler in line, which also decides not to handle this request and returns control back to its caller. This process continues until one of the handlers decides that it wants to handle this request, at which point it will return control back up through all remaining handlers in line until one finally ends up back at its caller (the client). At this point, all remaining handlers have been skipped over for this particular request and so cannot be asked again for any future requests that happen later on down

Post a Comment

Please do not post any spam link in the comment box😊

Previous Post Next Post

Blog ads

CodeGuru