Chain of Responsibility - Design Pattern

Chain of Responsibility - Design Pattern

Software Architecture Simplified

ยท

3 min read

Objective ๐ŸŽฏ

Allow a single request to be processed by multiple handlers in the chain. Each handler will decide either to process the request or to pass it to the next handler in the chain.

image.png

Type โœ…

โœ”๏ธBehavioral: Describes how objects interact/communicate between themselves.

โŒCreational: Describes how to instantiate an object without large and complex.

โŒStructural: Describes how objects/classes are composed to form larger structures.

UML ๐Ÿ“

image.png

Participants ๐Ÿ”—

โ€ข Handler:

  • Defines an interface for handling the requests

โ€ข Concrete Handler:

  • Implements Handler interface
  • Handles the request, either processing it or passing it to the successor handler

โ€ข Client:

  • Initiates the flow by forwarding the request to a Concrete Handler object

Sample Code ๐ŸŽฎ

Structural Example ๐Ÿ›๏ธ

image.png

public static class ChainOfResponsibilityStructural
    {
        public static void Execute()
        {
            Handler lConcreteHandler1 = new ConcreteHandler1();
            Handler lConcreteHandler2 = new ConcreteHandler2();
            Handler lConcreteHandler3 = new ConcreteHandler3();

            lConcreteHandler1.SetSuccessor(lConcreteHandler2);
            lConcreteHandler2.SetSuccessor(lConcreteHandler3);

            lConcreteHandler1.HandleRequest("AAA");
            lConcreteHandler1.HandleRequest("BBB");
        }
    }

    public abstract class Handler
    {
        protected Handler _SuccessorHandler;
        public void SetSuccessor(Handler prSuccessorHandler)
        {
            _SuccessorHandler = prSuccessorHandler;
        }
        public abstract void HandleRequest(string prRequest);
    }

    public class ConcreteHandler1 : Handler
    {
        public override void HandleRequest(string prRequest)
        {
            Console.WriteLine("ConcreteHandler1 - Handling Request: " + prRequest);

            if (_SuccessorHandler != null)
                _SuccessorHandler.HandleRequest(prRequest);
        }
    }

    public class ConcreteHandler2 : Handler
    {
        public override void HandleRequest(string prRequest)
        {
            Console.WriteLine("ConcreteHandler2 - Handling Request: " + prRequest);

            if (_SuccessorHandler != null)
                _SuccessorHandler.HandleRequest(prRequest);
        }
    }

    public class ConcreteHandler3 : Handler
    {
        public override void HandleRequest(string prRequest)
        {
            Console.WriteLine("ConcreteHandler3 - Handling Request: " + prRequest);

            if (_SuccessorHandler != null)
                _SuccessorHandler.HandleRequest(prRequest);
        }
    }

Output

image.png

Real-world Example ๐Ÿ”ฅ

image.png

public static class ChainOfResponsibilityPractical
    {
        public static void Execute()
        {
            Approver lAssistantManager = new AssistantManager();
            Approver lManager = new Manager();
            Approver lDirector = new Director();

            lAssistantManager.SetSuccessor(lManager);
            lManager.SetSuccessor(lDirector);

            Console.WriteLine("---------------------------------------------------------------");
            Console.WriteLine("Requesting approval for a order of cost USD 50.");
            lAssistantManager.ApproveOrder(50);
            Console.WriteLine("---------------------------------------------------------------");
            Console.WriteLine("Requesting approval for a order of cost USD 250.");
            lAssistantManager.ApproveOrder(250);
            Console.WriteLine("---------------------------------------------------------------");
            Console.WriteLine("Requesting approval for a order of cost USD 500.");
            lAssistantManager.ApproveOrder(500);
            Console.WriteLine("---------------------------------------------------------------");
            Console.WriteLine("Requesting approval for a order of cost USD 600.");
            lAssistantManager.ApproveOrder(600);
        }
    }

    public abstract class Approver
    {
        protected Approver _SuccessorApprover;
        public void SetSuccessor(Approver prApprover)
        {
            _SuccessorApprover = prApprover;
        }
        public abstract void ApproveOrder(int prCost);
    }

    public class AssistantManager : Approver
    {
        public override void ApproveOrder(int prCost)
        {
            if (prCost <= 50)
                Console.WriteLine("Assistant Manager - Order Approved. Cost: USD" + prCost);
            else
            {
                Console.WriteLine("Assistant Manager - Can't approve (cost > 50), sending to next approver in the hierarchy.");

                if (_SuccessorApprover != null)
                    _SuccessorApprover.ApproveOrder(prCost);
            }
        }
    }

    public class Manager : Approver
    {
        public override void ApproveOrder(int prCost)
        {
            if (prCost <= 250)
                Console.WriteLine("Manager - Order Approved. Cost: USD" + prCost);
            else
            {
                Console.WriteLine("Manager - Can't approve (cost > 250), sending to next approver in the hierarchy.");

                if (_SuccessorApprover != null)
                    _SuccessorApprover.ApproveOrder(prCost);
            }
        }
    }

    public class Director : Approver
    {
        public override void ApproveOrder(int prCost)
        {
            if (prCost <= 500)
                Console.WriteLine("Director - Order Approved. Cost: USD" + prCost);
            else
                Console.WriteLine("Director - Not approved, cost is too high");
        }
    }

Output

image.png

Source Code ๐ŸŽฒ

github.com/VictorLins/DesignPatterns

Did you find this article valuable?

Support Victor Lins by becoming a sponsor. Any amount is appreciated!

ย