Chain of Responsibility
Lets you 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.
classDiagram
class Handler {
<<interface>>
+setNext(Handler)
+handle(request)
}
class BaseHandler {
-Handler next
+setNext(Handler)
+handle(request)
}
class ConcreteHandler1 {
+handle(request)
}
class ConcreteHandler2 {
+handle(request)
}
class Client {
+operation()
}
Handler <|.. BaseHandler
BaseHandler <|-- ConcreteHandler1
BaseHandler <|-- ConcreteHandler2
Client --> Handler
When to use
Use when your program is expected to process different kinds of requests in various ways, but the exact types of requests and their sequences are unknown beforehand. Use when it’s essential to execute several handlers in a particular order.
Explanation
Problem
Imagine that you’re working on an online ordering system. You want to restrict access to the system so only authenticated users can create orders. Also, users who have administrative permissions must have full access to all orders.
As you added more checks (data validation, brute force detection, caching), the code became a mess. Changing one check sometimes broke the others.
Solution
The Chain of Responsibility relies on transforming particular behaviors into stand-alone objects called handlers. In our case, each check should be extracted to its own class with a single method that performs the check. The request, along with its data, is passed to this method as an argument.
The pattern suggests that you link these handlers into a chain. Each linked handler has a field for storing a reference to the next handler in the chain. In addition to processing a request, handlers pass the request further along the chain.
Real world problem
- Tech Support: Automated answering machine. Level 1 (Robot) -> Level 2 (General Support) -> Level 3 (Engineer).
- UI Event Bubbling: A click on a button fires an event. If the button doesn’t handle it, it bubbles up to the parent container, eventually to the window.
- Middlewares: Express.js or Laravel middleware. Auth -> Validation -> Logging -> Controller.
Pros and Cons
| Pros | Cons |
|---|---|
| - Control: You can control the order of request handling. - Single Responsibility Principle: You can decouple classes that invoke operations from classes that perform operations. - Open/Closed Principle: You can introduce new handlers into the app without breaking the existing client code. |
- Uncaught requests: Some requests may end up unhandled. |
Comparison
- Command: Chain of Responsibility creates a chain of potential receivers. Command connects a sender with a specific receiver.
- Mediator: Chain of Responsibility passes a request sequentially. Mediator sends it to many components or a specific one indirectly.
- Decorator: Decorators and Handlers have similar structures. Decorators wrap objects to add behavior. Handlers pass requests along a chain.
Code example
Typescript
Php