Simple explanation for Chain of Responsibility Pattern
Situation: You’re Building an HTTP Request Handler
You write a class HttpRequestHandler
to process incoming API requests.
Initially, it just needs to:
- Authenticate the user
- Validate the request body
- Process the request
All good.
Then Requirements Changed
Suddenly you need to:
- Add rate limiting
- Add logging
- Add feature flag check
- Add IP whitelisting
- And maybe do all this only in certain environments
Now you’re like:
“Should I just throw everything inside HttpRequestHandler? Maybe with 10 if-else blocks?”
But deep down, you know it’s a trap.
What’s the Problem?
- You’re turning one class into a god object.
- Every new rule = more clutter.
- You can’t re-use or reorder logic easily.
- Testing individual behaviors becomes painful.
- Changing one thing might break another.
How Chain of Responsibility Saves You
Instead of one big handler, you create a chain of small handlers, each doing one job:
AuthHandler
→ checks authenticationRateLimitHandler
→ checks quotaValidationHandler
→ validates inputBusinessLogicHandler
→ executes actual logic
Each handler:
- Implements a common interface (e.g.,
handleRequest
). - Decides to process the request, stop the chain (e.g., reject invalid input), or pass it to the next handler.
- If no next handler exists, the chain ends with a default action (e.g., return a response).
You can now add, remove, or reorder handlers without touching others. Super clean. Super flexible.
When Should You Use It?
- When a request needs to pass through multiple processing steps.
- When steps might be optional, conditional, or environment-dependent.
- When you want to decouple concerns - each class focuses on just one job.
Real World Dev Examples
- Middleware in Express.js or Spring Security Filters? Pure CoR.
- Event pipelines, logging systems, email processors? All use it.
- Support tickets getting escalated? That’s CoR in real life.