Chain of Responsibility Design Patten in C#

The Chain of Responsibility Design Pattern is a behavioral design pattern that allows you to create a chain of objects. Each object in the chain can handle a specific request or pass it to the next handler in the chain. It’s useful when you want to decouple senders and receivers of requests and allow multiple objects to process the request without the sender needing to know which object will ultimately handle it.

Here’s a C# example of the Chain of Responsibility Design Pattern with a use case for processing purchase requests:

Create the Handler Interface

Define an interface that declares a method for handling requests and optionally a reference to the next handler in the chain.

public abstract class PurchaseHandler
{
    protected PurchaseHandler successor;

    public void SetSuccessor(PurchaseHandler successor)
    {
        this.successor = successor;
    }

    public abstract void ProcessRequest(Purchase purchase);
}

Create Concrete Handlers

Implement concrete handler classes that inherit from the handler interface. Each handler can decide whether to process the request or pass it to the next handler in the chain.

public class Manager : PurchaseHandler
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 1000)
        {
            Console.WriteLine($"{purchase.Product} approved by Manager");
        }
        else if (successor != null)
        {
            successor.ProcessRequest(purchase);
        }
    }
}

public class Director : PurchaseHandler
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 5000)
        {
            Console.WriteLine($"{purchase.Product} approved by Director");
        }
        else if (successor != null)
        {
            successor.ProcessRequest(purchase);
        }
    }
}

public class VicePresident : PurchaseHandler
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 10000)
        {
            Console.WriteLine($"{purchase.Product} approved by Vice President");
        }
        else if (successor != null)
        {
            successor.ProcessRequest(purchase);
        }
    }
}

public class President : PurchaseHandler
{
    public override void ProcessRequest(Purchase purchase)
    {
        Console.WriteLine($"{purchase.Product} approved by President");
    }
}

Create the Request Class

Define a class to represent the request, in this case, a purchase request.

public class Purchase
{
    public string Product { get; set; }
    public double Amount { get; set; }

    public Purchase(string product, double amount)
    {
        Product = product;
        Amount = amount;
    }
}

Use Case – Processing Purchase Requests

Use the Chain of Responsibility pattern to process purchase requests through the chain of handlers.

class Program
{
    static void Main(string[] args)
    {
        PurchaseHandler manager = new Manager();
        PurchaseHandler director = new Director();
        PurchaseHandler vp = new VicePresident();
        PurchaseHandler president = new President();

        manager.SetSuccessor(director);
        director.SetSuccessor(vp);
        vp.SetSuccessor(president);

        Purchase purchase1 = new Purchase("Laptop", 900);
        Purchase purchase2 = new Purchase("Projector", 5500);
        Purchase purchase3 = new Purchase("Conference Table", 15000);

        manager.ProcessRequest(purchase1);
        manager.ProcessRequest(purchase2);
        manager.ProcessRequest(purchase3);
    }
}

In this example, the Chain of Responsibility Design Pattern allows different handlers (Manager, Director, Vice President, and President) to process purchase requests based on their respective approval limits. If a handler can’t approve a request, it passes it to the next handler in the chain. This pattern helps maintain a loosely coupled and extensible way to process requests without the client needing to know the specific handler.