Chain Of Responsibility Pattern

  • Behavioral pattern
  • The intent of this pattern is to avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. It does that by chaining the receiving objects passing the request along the chain until an object handles it.
  • Each Handler checks whether it can handle the request or not. If it can’t the requst is passed on. If it can, the request is handled and no longer passed on.
  • Handler defines an interface for handling requests, and optionally implements the successor link
  • ConcreteHandler handles the request its responsible for. It can access the successor and potentially pass the request on. 
  • Client initiates the request to ConcreteHandler object on the chain.
				
					namespace chainofresponsibility
{
   public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool IsCurrentEmployee { get; set; }
        public bool BackgroundVerificationCleared { get; set; }
        public bool IsProjectAllocated { get; set; }
        public string Designation { get; set; }

        public Employee(int id, string name, bool isCurrentEmployee, bool backgroundVerificationCleared, bool isProjectAllocated, string designation)
        {
            Id = id;
            Name = name;
            IsCurrentEmployee = isCurrentEmployee;
            BackgroundVerificationCleared = backgroundVerificationCleared;
            IsProjectAllocated = isProjectAllocated;
            Designation = designation;
        }
    }

    public interface IHandler<T> where T : class
    {
        IHandler<T> SetSuccessor(IHandler<T> successor);
        void Handle(T request);
    }

    public class EmployeeNotResignedHandler : IHandler<Employee>
    {
        private IHandler<Employee>? _successor;
        public void Handle(Employee request)
        {
            if (!request.IsCurrentEmployee)
            {
                throw new Exception("Employee has resigned");
            }
            _successor?.Handle(request);
        }

        public IHandler<Employee> SetSuccessor(IHandler<Employee> successor)
        {
            _successor=successor;
            return _successor;
        }
    }

    public class EmployeeBackgroundVerificationHandler : IHandler<Employee>
    {
        private IHandler<Employee>? _successor;
        public void Handle(Employee request)
        {
            if (!request.BackgroundVerificationCleared)
            {
                throw new Exception("Employees background verification is not cleared");
            }
            _successor?.Handle(request);
        }

        public IHandler<Employee> SetSuccessor(IHandler<Employee> successor)
        {
            _successor = successor;
            return _successor;
        }
    }

    public class EmployeeProjectAllocatedHandler : IHandler<Employee>
    {
        private IHandler<Employee>? _successor;
        public void Handle(Employee request)
        {
            if (!request.IsProjectAllocated)
            {
                throw new Exception("Employee is is bench !!");
            }
            _successor?.Handle(request);
        }

        public IHandler<Employee> SetSuccessor(IHandler<Employee> successor)
        {
            _successor = successor;
            return _successor;
        }
    }

    public class EmployeeManagerHandler : IHandler<Employee>
    {
        private IHandler<Employee>? _successor;
        public void Handle(Employee request)
        {
            if (request.Designation != "Manager")
            {
                throw new Exception("Employee is not manager !!");
            }
            Console.WriteLine("Employee is manager");
        }

        public IHandler<Employee> SetSuccessor(IHandler<Employee> successor)
        {
            _successor = successor;
            return _successor;
        }
    }
}

				
			
				
					// See https://aka.ms/new-console-template for more information



using chainofresponsibility;

var employee1 = new Employee(123,"Anurag",true,true,true,"Manager");
var employee2 = new Employee(124,"Abhishek",true,true,true,"Developer");

var handler = new EmployeeNotResignedHandler();
handler.SetSuccessor(new EmployeeBackgroundVerificationHandler())
       .SetSuccessor(new EmployeeProjectAllocatedHandler())
       .SetSuccessor(new EmployeeManagerHandler());


try
{
    handler.Handle(employee1);
    handler.Handle(employee2);
    Console.WriteLine("Employee is valid and employee is Manager");
}
catch (Exception ex)
{
    Console.WriteLine("Employee is not valid/manager!!");
}
				
			

Employee is manager
Employee is not valid/manager!!

Leave a Comment