Introduction
Imagine you are building a customer support system.
Whenever a customer raises a ticket, the ticket may need to be handled by different support levels:
Level 1 Support
Level 2 Support
Manager
Director
A simple issue might be resolved by Level 1 Support.
A technical issue might be forwarded to Level 2 Support.
A business-critical issue may eventually reach the Director.
Now imagine writing code like this:
This works initially.
But as the organization grows:
More handlers are added
Request types increase
Rules become complex
The code becomes difficult to maintain.
The Chain of Responsibility Pattern provides a much cleaner solution.
What is the Chain of Responsibility Pattern?
The Chain of Responsibility Pattern is a behavioral design pattern that allows a request to pass through a chain of handlers until one of them handles it.
In simple words:
A request travels through multiple handlers until someone takes responsibility for processing it.
The sender does not need to know which object will handle the request.
Real World Analogy
Imagine you visit a bank.
You need approval for a loan.
The request moves through different people:
Clerk
↓
Senior Officer
↓
Branch Manager
↓
Regional Manager
Each person checks:
"Can I handle this request?"
If yes:
Process Request
If no:
Forward To Next Person
This is exactly how the Chain of Responsibility Pattern works.
Why Do We Need the Chain of Responsibility Pattern?
Consider an expense approval system.
Approval rules:
Amount <= 10,000 → Team Lead
Amount <= 50,000 → Manager
Amount <= 2,00,000 → Director
Amount > 2,00,000 → CEO
Without Chain of Responsibility:
This creates several problems.
Problems Without Chain of Responsibility
1. Tight Coupling
The client knows every handler.
Client
├── Team Lead
├── Manager
├── Director
└── CEO
2. Difficult to Extend
Adding a new approval level requires modifying existing code.
3. Violates the Open-Closed Principle
Every new handler requires changing the if-else logic.
4. Complex Conditional Statements
As rules grow, conditions become harder to maintain.
Solution: Chain of Responsibility Pattern
The Chain of Responsibility Pattern creates a chain of handlers.
Instead of:
Client decides handler
We do:
Client
↓
Handler 1
↓
Handler 2
↓
Handler 3
↓
Handler 4
Each handler decides:
Can I handle this request?
If yes:
Handle Request
If no:
Forward To Next Handler
Key Components of the Chain of Responsibility Pattern
The pattern usually consists of:
1. Handler Interface
Defines request handling behavior.
2. Concrete Handlers
Actual implementations that process requests.
3. Chain
Links handlers together.
4. Client
Sends requests into the chain.
Structure of the Chain of Responsibility Pattern
Request
│
▼
Handler A
│
▼
Handler B
│
▼
Handler C
│
▼
Handler D
The request keeps moving until a handler processes it.
Example: Expense Approval System
Let's implement an expense approval workflow.
Step 1: Create Request Class
Step 2: Create Handler Interface
Step 3: Create Team Lead Handler
Step 4: Create Manager Handler
Step 5: Create Director Handler
Step 6: Create CEO Handler
Step 7: Create the Chain
Output
Approved by Director
How the Chain Works
Let's follow the request flow.
Request:
ExpenseRequest(75000)
First handler:
Team Lead
Check:
75000 <= 10000 ?
No.
Forward.
Next:
Manager
Check:
75000 <= 50000 ?
No.
Forward.
Next:
Director
Check:
75000 <= 200000 ?
Yes.
The request is handled.
Key Idea Behind the Pattern
The most important idea is:
Give multiple objects an opportunity to handle a request without the sender knowing which object will handle it.
The client simply submits the request.
The chain decides where it should go.
Request Can Be Handled by Multiple Handlers
Sometimes every handler processes the request.
Example:
Authentication Middleware
↓
Logging Middleware
↓
Authorization Middleware
↓
Business Logic
Each handler performs some work before passing the request forward.
This is very common in web frameworks.
Chain of Responsibility vs Strategy Pattern
| Chain of Responsibility | Strategy |
|---|---|
| Multiple handlers exist | One strategy is selected |
| Request travels through the chain | The algorithm executes directly |
| The handler decides whether to process | Client selects behavior |
| Focuses on request routing | Focuses on algorithm selection |
Chain of Responsibility vs Command Pattern
| Chain of Responsibility | Command |
|---|---|
| Decides who handles the request | Encapsulates the request as an object |
| Multiple possible handlers | One receiver usually executes |
| Request forwarding is important | Execution is important |
Advantages of Chain of Responsibility
1. Loose Coupling
The sender does not know the receiver.
2. Easy Extensibility
New handlers can be added easily.
3. Supports the Open-Closed Principle
New behavior can be added without modifying existing handlers.
4. Cleaner Code
Eliminates large conditional statements.
5. Flexible Request Routing
Requests can be dynamically routed through different chains.
Disadvantages of the Chain of Responsibility
1. Request May Go Unhandled
If no handler processes the request, it may be lost.
Example:
Handler A
↓
Handler B
↓
End of Chain
No handler accepts the request.
2. Difficult Debugging
Tracing the request path can become difficult in large systems.
3. Performance Overhead
Very long chains can increase processing time.
Real World Applications
The Chain of Responsibility Pattern is widely used in:
Customer support escalation systems
Expense approval workflows
Banking approval systems
Middleware frameworks
Authentication pipelines
Logging frameworks
Event processing systems
Web request processing
Exception handling frameworks
Many modern web frameworks internally implement middleware using this pattern.
Common Beginner Mistakes
1. Forgetting to Forward Requests
A handler should forward the request when it cannot process it.
Example:
nextApprover->approve(request);
2. Creating Circular Chains
Avoid:
A → B → C → A
This creates infinite loops.
3. Putting All Logic in One Handler
The responsibility should be distributed across handlers.
4. Making the Client Aware of All Handlers
The client should only interact with the start of the chain.
Simple Visualization
Without Chain of Responsibility:
Client
├── Team Lead
├── Manager
├── Director
└── CEO
The client knows everyone.
With Chain of Responsibility:
Client
│
▼
Team Lead
│
▼
Manager
│
▼
Director
│
▼
CEO
The client only knows the first handler.
Summary
The Chain of Responsibility Pattern allows a request to pass through a sequence of handlers until one of them processes it.
Instead of tightly coupling the sender to a specific receiver, the request flows through a chain where each handler decides whether to handle it or forward it further. This creates more flexible, extensible, and maintainable systems while eliminating large conditional statements.
Whenever multiple objects may be capable of handling a request, and you want to avoid hardcoding the receiver, the Chain of Responsibility Pattern provides a clean and scalable solution.