Better Use Case for Chain of Responsibility Pattern: Is It Just a Replacement for Multiple If-Else Statements?

Unraveling the Power of Chain of Responsibility Beyond Simple Conditional Logic

DotNet Full Stack Dev
4 min readDec 28, 2024

The Chain of Responsibility (CoR) pattern is a behavioral design pattern that delegates tasks along a chain of handlers. At first glance, it may seem like a fancy alternative to multiple if-else statements, but its real power lies in its ability to decouple request senders from receivers and create flexible chains of operations.

In this blog, we’ll explore:

  • What the Chain of Responsibility pattern is.
  • A comparison with multiple if-else statements.
  • The scenarios where CoR truly shines.
  • A real-world implementation in .NET Core.

📌Explore more at: https://dotnet-fullstack-dev.blogspot.com/
🌟 Clapping would be appreciated! 🚀

What Is the Chain of Responsibility Pattern?

The Chain of Responsibility pattern creates a chain of objects where each object decides whether to handle a request or pass it to the next object in the chain. This provides:

  • Decoupling: The sender does not need to know who will handle the request.
  • Extensibility: Adding or removing handlers does not impact other parts of the chain.

How It Works

  1. A client sends a request.
  2. Each handler in the chain either processes the request or forwards it to the next handler.
  3. The chain ends when a handler processes the request or no handler is left.

Comparison: Chain of Responsibility vs Multiple If-Else

Multiple If-Else Statements

In a straightforward scenario, you might use multiple if-else statements to handle conditions.

Example:

public class DiscountHandler
{
public string ApplyDiscount(decimal amount)
{
if (amount > 1000)
{
return "10% discount applied.";
}
else if (amount > 500)
{
return "5% discount applied.";
}
else
{
return "No discount.";
}
}
}

Drawbacks:

  1. Tightly Coupled Logic: Hard to add, remove, or reorder conditions.
  2. Rigid Code: Scaling becomes difficult as new conditions are added.
  3. Single Responsibility Violation: Mixing logic for condition checking and action processing.

Chain of Responsibility Pattern

The Chain of Responsibility solves these issues by separating conditions into discrete handlers.

Example:

public abstract class DiscountHandler
{
protected DiscountHandler _nextHandler;

public void SetNext(DiscountHandler nextHandler)
{
_nextHandler = nextHandler;
}

public abstract string Handle(decimal amount);
}

public class HighDiscountHandler : DiscountHandler
{
public override string Handle(decimal amount)
{
if (amount > 1000)
{
return "10% discount applied.";
}
else if (_nextHandler != null)
{
return _nextHandler.Handle(amount);
}
return "No discount.";
}
}

public class MediumDiscountHandler : DiscountHandler
{
public override string Handle(decimal amount)
{
if (amount > 500)
{
return "5% discount applied.";
}
else if (_nextHandler != null)
{
return _nextHandler.Handle(amount);
}
return "No discount.";
}
}

Benefits of CoR Over If-Else

When to Use Chain of Responsibility

While CoR can replace if-else statements, its real power lies in more complex scenarios:

1. Request Processing Pipelines

Example: A logging framework where logs pass through different handlers (e.g., console, file, or remote server).

2. Validation Chains

Example: Validating user input where each handler validates a specific rule (e.g., email, phone number, password strength).

3. Conditional Workflows

Example: An e-commerce checkout process with handlers for discount application, tax calculation, and payment processing.

Real-World Example in .NET Core

Scenario: Logging Framework

We’ll create a logging framework that processes log messages based on their severity.

Step 1: Define the Base Handler

public abstract class LogHandler
{
protected LogHandler _nextHandler;

public void SetNext(LogHandler nextHandler)
{
_nextHandler = nextHandler;
}

public abstract void Handle(string message, LogLevel level);
}

public enum LogLevel
{
Info,
Warning,
Error
}

Step 2: Implement Handlers

public class ConsoleLogHandler : LogHandler
{
public override void Handle(string message, LogLevel level)
{
if (level == LogLevel.Info)
{
Console.WriteLine($"Console Log: {message}");
}
else if (_nextHandler != null)
{
_nextHandler.Handle(message, level);
}
}
}

public class FileLogHandler : LogHandler
{
public override void Handle(string message, LogLevel level)
{
if (level == LogLevel.Warning)
{
Console.WriteLine($"File Log: {message}");
// Simulate writing to a file
}
else if (_nextHandler != null)
{
_nextHandler.Handle(message, level);
}
}
}

public class ErrorLogHandler : LogHandler
{
public override void Handle(string message, LogLevel level)
{
if (level == LogLevel.Error)
{
Console.WriteLine($"Error Log: {message}");
}
else if (_nextHandler != null)
{
_nextHandler.Handle(message, level);
}
}
}

Step 3: Create the Chain

public class Program
{
static void Main()
{
var consoleHandler = new ConsoleLogHandler();
var fileHandler = new FileLogHandler();
var errorHandler = new ErrorLogHandler();

consoleHandler.SetNext(fileHandler);
fileHandler.SetNext(errorHandler);

// Start the chain
consoleHandler.Handle("This is an info message.", LogLevel.Info);
consoleHandler.Handle("This is a warning message.", LogLevel.Warning);
consoleHandler.Handle("This is an error message.", LogLevel.Error);
}
}

Output:

Console Log: This is an info message.
File Log: This is a warning message.
Error Log: This is an error message.

Conclusion

While the Chain of Responsibility pattern can replace multiple if-else statements, it offers much more:

  • It simplifies complex workflows.
  • Makes code scalable and maintainable.
  • Enhances readability and modularity.

For simple scenarios, if-else might suffice. However, for dynamic, extensible, and decoupled solutions, the Chain of Responsibility pattern is your go-to approach.

Which use case have you used Chain of Responsibility for? Share your thoughts in the comments below!

--

--

DotNet Full Stack Dev
DotNet Full Stack Dev

Written by DotNet Full Stack Dev

Join me to master .NET Full Stack Development & boost your skills by 1% daily with insights, examples, and techniques! https://dotnet-fullstack-dev.blogspot.com

Responses (1)