Chain of Responsibility pattern in C#
Hello, C# lovers! 😍
Today I want to talk about a very useful design pattern called Chain of Responsibility. This pattern allows you to pass a request along a chain of handlers until one of them can handle it. This way, you can avoid coupling the sender of the request with the receiver, and you can dynamically compose the chain at runtime. Sounds cool, right? 😎
Let’s see an example of how to implement this pattern in C#. Suppose you have a simple ATM machine that can dispense bills of 10, 20, and 50 dollars. You want to write a program that can handle any amount of money requested by the user, using the least number of bills possible.
To do this, you can create an abstract class called Handler that defines an interface for handling the requests. It also has a reference to the next handler in the chain, and a method to set it.
// The 'Handler' abstract class
public abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int amount);
}
Then, you can create concrete subclasses for each type of bill: 10, 20 and 50 dollars. Each subclass overrides the HandleRequest method and checks if it can handle the request. If it can, it dispenses the bill and reduces the amount by its value. If it cannot, or if there is some remaining amount, it passes the request to the next handler in the chain.
// The 'ConcreteHandler1' class for 10 dollar bills
public class TenDollarHandler : Handler
{
public override void HandleRequest(int amount)
{
if (amount >= 10)
{
int num = amount / 10;
int rem = amount % 10;
Console.WriteLine($"Dispensing {num} 10$ bill(s)");
if (rem != 0)
{
successor?.HandleRequest(rem);
}
}
else
{
successor?.HandleRequest(amount);
}
}
}
// The 'ConcreteHandler2' class for 20 dollar bills
public class TwentyDollarHandler : Handler
{
public override void HandleRequest(int amount)
{
if (amount >= 20)
{
int num = amount / 20;
int rem = amount % 20;
Console.WriteLine($"Dispensing {num} 20$ bill(s)");
if (rem != 0)
{
successor?.HandleRequest(rem);
}
}
else
{
successor?.HandleRequest(amount);
}
}
}
// The 'ConcreteHandler3' class for 50 dollar bills
public class FiftyDollarHandler : Handler
{
public override void HandleRequest(int amount)
{
if (amount >= 50)
{
int num = amount / 50;
int rem = amount % 50;
Console.WriteLine($"Dispensing {num} 50$ bill(s)");
if (rem != 0)
{
successor?.HandleRequest(rem);
}
}
else
{
successor?.HandleRequest(amount);
}
}
}
Finally, you can create a client class that sets up the chain of handlers and initiates the request.
// The 'Client' class
public class ATM
{
private Handler handler;
public ATM()
{
// Setup Chain of Responsibility
handler = new FiftyDollarHandler();
Handler handler2 = new TwentyDollarHandler();
Handler handler3 = new TenDollarHandler();
handler.SetSuccessor(handler2);
handler2.SetSuccessor(handler3);
}
public void Withdraw(int amount)
{
// Process the request
handler.HandleRequest(amount);
}
}
Now you can test your program with different amounts of money and see how it works.
// The 'Main' method
static void Main(string[] args)
{
ATM atm = new ATM();
// Withdraw 90 dollars
Console.WriteLine("Withdrawing 90$...");
atm.Withdraw(90);
// Withdraw 40 dollars
Console.WriteLine("Withdrawing 40$...");
atm.Withdraw(40);
// Withdraw 75 dollars
Console.WriteLine("Withdrawing 75$...");
atm.Withdraw(75);
}
The output should look something like this:
Withdrawing 90$...
Dispensing 1 50$ bill(s)
Dispensing 2 20$ bill(s)
Withdrawing 40$...
Dispensing 2 20$ bill(s)
Withdrawing 75$...
Dispensing 1 50$ bill(s)
Dispensing 1 20$ bill(s)
Dispensing 1 10$ bill(s)
As you can see, the Chain of Responsibility pattern is very handy when you have a series of objects that can handle a request in different ways. You can also add or remove handlers from the chain without affecting the client code. 🙌
If you want to learn more about this pattern, you can check out these links:
- Design Patterns: Chain of Responsibility in C# - A great tutorial with diagrams and code examples.
- C# Chain of Responsibility Design Pattern - Another tutorial with UML class diagrams and structural code.
- 8 Steps to Understand the Chain of Responsibility Pattern in C# - A step-by-step guide to understand the concept and implementation of this pattern.
I hope you enjoyed this article and learned something new. If you did, please share it with your friends and colleagues. And don’t forget to subscribe to my blog for more awesome C# content. 😊
You can find the code examples here: source code
Happy coding! 👩💻👨💻
Comments
Post a Comment