Design Patterns

Last Updated: 10/3/2024

Chain of Responsibility

  • You use this pattern when you need a pipeline or chain of objects for processing the request

Classical Structure

Chain of Responsibility Classical Structure

Scenario

  • Build a web server that process the request

Problem

  • Webserver is tightly coupled with authentication
  • Order of action is hardcoded in the class
internal class Authenticator
{
    public bool Authenticate(HttpRequest request)
    {
        Console.WriteLine("Authenticating request");
        return request.Username == "admin" && request.Password == "admin";
    }
}
internal class Compressor
{
    public void Compress(HttpRequest request)
    {
        Console.WriteLine("Compress request");
    }
}
internal class Logger
{
    public void Log(HttpRequest request)
    {
        Console.WriteLine("Logging request");
    }
}
internal class HttpRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}
internal class Webserver
{
    public void Handle()
    {
        //Authenticate
        var authenticator = new Authenticator();
        authenticator.Authenticate(new HttpRequest { Username = "admin", Password = "admin" });

        //Log

        //Compress 
    }
}

Solution

internal class HttpRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}
internal abstract class Handler
{
    private Handler next;

    protected Handler(Handler next)
    {
        this.next = next;
    }

    public void Handle(HttpRequest request)
    {
        if (DoHandle(request))
            return;

        if(next != null)
            next.Handle(request);
    }

    protected abstract bool DoHandle(HttpRequest request);
}
internal class Authenticator : Handler
{
    public Authenticator(Handler next) : base(next)
    {
    }

    protected override bool DoHandle(HttpRequest request)
    {
        Console.WriteLine("Authenticating request");
        return !(request.Username == "admin" && request.Password == "admin");
    }
}
internal class Compressor : Handler
{
    public Compressor(Handler next) : base(next)
    {
    }

    public void Compress(HttpRequest request)
    {
        Console.WriteLine("Compress request");
    }

    protected override bool DoHandle(HttpRequest request)
    {
        Console.WriteLine("Compressing");
        return false;
    }
}
internal class Logger: Handler
{
    public Logger(Handler next) : base(next)
    {
    }

    protected override bool DoHandle(HttpRequest request)
    {
        Console.WriteLine("Logging request");
        return false;
    }
}
internal class Webserver
{
    private Handler handler;

    public Webserver(Handler handler)
    {
        this.handler = handler;
    }

    public void Handle(HttpRequest request)
    {
        handler.Handle(request);
    }
}
public class Program
{
    static void Main(string[] args)
    {
        var compressor = new Compressor(null);
        var logger = new Logger(compressor);
        var authenticator = new Authenticator(logger);
        var webserver = new Webserver(authenticator);
        webserver.Handle(new HttpRequest { Username = "admin", Password = "admin123"});
    }
}

Example Structure

Pipeline Example Structure

Example Code