The Chain of Responsibility Pattern

The Chain of Responsibility Pattern

Introduction

The Chain of Responsibility Pattern is a powerful tool for handling requests sequentially through a chain of handlers.

This pattern decouples senders and receivers, promoting flexible and adaptable handling of requests.

Understanding the Chain of Responsibility Pattern

The Chain of Responsibility Pattern revolves around the concept of a chain of handlers, where each handler can handle a request or pass it on to the next handler in the chain.

This pattern promotes flexible and decoupled handling of requests, avoiding rigid object relationships.

Benefits of the Chain of Responsibility Pattern

The Chain of Responsibility Pattern offers several advantages, including:

  • Decoupled Request Handling: It decouples senders and receivers, promoting flexible and adaptable request handling.
  • Dynamic Request Routing: It allows for dynamic routing of requests based on their content or context.
  • Simplified Client Code: It simplifies client code by reducing the need for explicit routing decisions.
  • Easier to Add New Handlers: It makes it easier to add new handlers without affecting existing ones.
  • Enhanced Modularity: It promotes modularity by making isolating and testing individual handlers easier.

Types of Chain of Responsibility Patterns

The Chain of Responsibility Pattern encompasses several variations:

  • Simple Chain of Responsibility: This pattern involves a single chain of handlers that can handle a specific type of request.
  • Multi-level Chain of Responsibility: This pattern introduces multiple chains of handlers, allowing for hierarchical request handling.
  • Multicast Chain of Responsibility: This pattern allows for multiple handlers to receive a copy of the request, enabling parallel processing.

Implementing the Chain of Responsibility Pattern in C#

To illustrate the implementation of the Chain of Responsibility Pattern in C#, consider a simplified scenario of handling logging requests:

Logger Interface

public interface ILogger
{
    void LogMessage(string message);
}

Concrete Logger Classes

public class ConsoleLogger : ILogger
{
    public void LogMessage(string message)
    {
        Console.WriteLine("Log message: " + message);
    }
}

public class FileLogger : ILogger
{
    public void LogMessage(string message)
    {
        // Write message to a file
        Console.WriteLine("Log message to file: " + message);
    }
}

Request Handler

public class RequestLogger
{
    private List<ILogger> loggers = new List<ILogger>();

    public void AddLogger(ILogger logger)
    {
        loggers.Add(logger);
    }

    public void LogRequest(string request)
    {
        foreach (ILogger logger in loggers)
        {
            logger.LogMessage("Request received: " + request);
        }
    }
}

Using the Logger

RequestLogger requestLogger = new RequestLogger();
requestLogger.AddLogger(new ConsoleLogger());
requestLogger.AddLogger(new FileLogger());

requestLogger.LogRequest("Request 1");
requestLogger.LogRequest("Request 2");

This example demonstrates a basic implementation of the Chain of Responsibility Pattern for handling logging requests.

Conclusion

The Chain of Responsibility Pattern is a versatile tool for managing requests in C# applications.

Decoupling senders and receivers promotes flexible and adaptable handling of requests, making it well-suited for handling complex request scenarios.

Developers can leverage this pattern to create robust and extensible software systems.

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.