The Chain of Responsibility is intended to promote loose coupling between the sender of a request and its receiver by giving more than one object an opportunity to handle the request. The receiving objects are chained and pass the request along the chain until one of the objects handles it.
What I like about this pattern is the chaining part. If the first handler cannot handle the request, the second one will. Or the third, fourth, or … And you only have to call the first handler of the chain.
You must be aware that if you want to use this pattern you should be very keen on exception handling, because the major drawback of this pattern is the possibility that the chain breaks.
And you probably heard this before:
A chain is only as strong as its weakest link
This also holds true for the chain of responsibility pattern. If one handler doesn’t do its work right the working of the following handlers are possibly compromised, which is especially important if the handler is one of the first components in the chain.
The client creates the chain by linking the handlers and does its request to the first handler in the chain, that’s it.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Client { static void Main() { Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); handler1.SetSuccessor(handler2); handler1.HandleRequest(1); handler1.HandleRequest(2); Console.ReadKey(); } } |
As is the case in most design patterns, there is an abstract class. The abstract class Handler defines SetSuccessor, which is responsible for the actual chaining.
|
1 2 3 4 5 6 7 8 9 10 11 |
abstract class Handler { protected Handler m_Successor; public void SetSuccessor(Handler successor) { this.m_Successor = successor; } public abstract void HandleRequest(int request); } |
The concrete class implements the actual handling of the request.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// first concrete Handler class ConcreteHandler1 : Handler { public override void HandleRequest(int request) { Console.Write("Request {0} is handled by Handler1", request); if (request == 1) { Console.WriteLine(); } else if (m_Successor != null) { Console.Write("->"); m_Successor.HandleRequest(request); } } } // second concrete Handler class ConcreteHandler2 : Handler { public override void HandleRequest(int request) { Console.Write("Handler2"); if (request == 2) { Console.WriteLine(); } else if (m_Successor != null) { Console.Write("->"); m_Successor.HandleRequest(request); } } } |
I also have included a real world example, a message handler which can handle different versions of requests. The first link in the chain handles version 1, the second version 2, and so forth…
Click here for a simplified
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
class Client { static void Main() { MessageHandler handler1 = new MessageHandler_v1(); MessageHandler handler2 = new MessageHandler_v2(); handler1.SetSuccessor(handler2); handler1.HandleRequest(".."); handler1.HandleRequest(".."); Console.ReadKey(); } } abstract class MessageHandler { protected MessageHandler m_Successor; public void SetSuccessor(MessageHandler successor) { this.m_Successor = successor; }public abstract void HandleRequest(Request request); } class MessageHandler_v1 : MessageHandler { public override void HandleRequest(Request request) { if (request.version == 1) { // Handle message } else if (m_Successor != null) { m_Successor.HandleRequest(request); } } } class MessageHandler_v2 : MessageHandler { public override void HandleRequest(Request request) { if (request.version == 1) { // Handle message } else if (m_Successor != null) { m_Successor.HandleRequest(request); } } } |
This post is part of my series on the foundational design patterns in C#. In this series we explore the ancient design patterns and their use in real-world programming situations of today. In these series of posts we explore each pattern and look at simplified real-world C# code that implements the pattern.
Comments