Chain of Responsibility Pattern
Pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
Intent & Objective
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along until an object handles it.
"If the tier-1 support agent cannot solve your billing issue, it passes to tier-2, and then to a senior manager until resolved."
"A legal dispute moves from local district court -> appellate court -> supreme court until a verdict is rendered."
"A student classroom issue moves from Teacher -> Principal -> School Board if unresolved."
"An unexpected regression defect moves from Developer -> QA -> Tech Lead -> Engineering Director."
The Problem
Hardcoding a single handler or giant if-else ladder to evaluate multi-stage requests (authentication -> rate limiting -> caching -> validation -> execution).
The Solution
Transform individual behaviors into standalone objects called handlers. Link handlers sequentially into a chain. Each handler has a reference to the next handler.
Key Participants & Architectural Roles
Code Samples (Traditional OOP vs Functional Programming)
Available in C++, Python, and JavaParadigm Contrast: Traditional OOP vs Functional / Data-Oriented
In OOP, Chain of Responsibility links objects via pointer chains. In Functional Programming, it is simply function composition of middleware functions `f(g(h(x)))` or reducing over a list of filter/validator functions.
Advantages
- β Controls the order of request processing dynamically
- β Single Responsibility Principle: decouples classes that invoke operations from classes that perform them
- β Open/Closed Principle: introduces new handlers without breaking existing code
Trade-offs
- β Some requests may end up unhandled if they reach the end of the chain without a match
When to Apply
- β When your program is expected to process different kinds of requests in various ways, but the exact request types and their orders are unknown beforehand
- β Web middleware pipelines (Express, Spring Security, ASP.NET Core)
When to Avoid
- ! When only a single guaranteed handler exists for all requests