Chain of Responsibility Pattern¶
Category: Behavioral Pattern
Overview¶
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 the chain until an object handles it, allowing multiple objects to handle a request without the sender knowing which object will ultimately process it.
Usage Guidelines¶
Use when:
- More than one object can handle a request
- Set of handlers should be determined at runtime
- Sender shouldn't know which handler processes the request
- Implementing middleware or filter chains
Avoid when:
- Only one object can handle requests
- Every request must be handled with guarantee
- Chain traversal overhead is unacceptable for performance
- Simple routing with direct handler selection is straightforward
Implementation¶
from typing import Optional
class RequestHandler:
"""Base class for handling requests in a chain of responsibility."""
def __init__(self, successor: Optional['RequestHandler'] = None) -> None:
"""Initializes the handler with an optional successor.
Args:
successor: The next handler in the chain.
"""
self.successor = successor
def handle(self, request: str) -> str:
"""Handles the request or passes it to the next handler.
Args:
request: The request to be handled.
Returns:
str: The result of the request.
"""
if self.successor:
return self.successor.handle(request)
return f"No handler for {request}"
class ApprovalRequestHandler(RequestHandler):
"""Handler that processes approval requests."""
def handle(self, request: str) -> str:
"""Handles specific requests for ApprovalRequestHandler.
Args:
request: The request to be handled.
Returns:
str: The result of handling the request.
"""
if request == "ApprovalRequest":
return "ApprovalRequestHandler handled ApprovalRequest"
return super().handle(request)
class EscalationRequestHandler(RequestHandler):
"""Handler that processes escalation requests."""
def handle(self, request: str) -> str:
"""Handles specific requests for EscalationRequestHandler.
Args:
request: The request to be handled.
Returns:
str: The result of handling the request.
"""
if request == "EscalationRequest":
return "EscalationRequestHandler handled EscalationRequest"
return super().handle(request)
Usage¶
# Creating the chain of responsibility
escalation_handler = EscalationRequestHandler()
approval_handler = ApprovalRequestHandler(escalation_handler)
# Testing the chain with different requests
print(approval_handler.handle("ApprovalRequest"))
# Output: ApprovalRequestHandler handled ApprovalRequest
print(approval_handler.handle("EscalationRequest"))
# Output: EscalationRequestHandler handled EscalationRequest
print(approval_handler.handle("FeedbackRequest"))
# Output: No handler for FeedbackRequest
Trade-offs¶
Benefits:
- Reduced coupling as sender doesn't need to know the receiver
- Flexibility to add or remove handlers at runtime
- Multiple objects share handling responsibility
- Single Responsibility Principle with each handler focused on one type
Drawbacks:
- Request might not be handled by any handler
- Chain traversal can be slow for performance
- Hard to track which handler processes request for debugging
- Long chains become difficult to manage
Real-World Examples¶
- GUI event propagation through widget hierarchy
- Logging frameworks with messages passing through handlers
- HTTP middleware request processing
- Support ticket escalation systems
Related Patterns¶
- Composite
- Command
- Decorator
API Reference¶
design_patterns.behavioral.chain_of_responsibility
¶
Chain of Responsibility Pattern Example
This module demonstrates the Chain of Responsibility design pattern in Python. It defines a series of handler classes that process requests. Each handler can either handle a request or pass it to the next handler in the chain.
Example
Creating a chain of handlers and testing it:
# Creating the chain of responsibility
handler_chain = ApprovalRequestHandler(EscalationRequestHandler())
# Testing the chain with different requests
print(handler_chain.handle("ApprovalRequest")) # Output: ApprovalRequestHandler handled ApprovalRequest
print(handler_chain.handle("EscalationRequest")) # Output: EscalationRequestHandler handled EscalationRequest
print(handler_chain.handle("FeedbackRequest")) # Output: No handler for FeedbackRequest
Classes:
| Name | Description |
|---|---|
RequestHandler |
Base class for handling requests. |
ApprovalRequestHandler |
Handles approval requests. |
EscalationRequestHandler |
Handles escalation requests. |
ApprovalRequestHandler
¶
Bases: RequestHandler
Handler that processes approval requests.
This handler is responsible for handling requests related to approvals.
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
handle(request)
¶
Handles specific requests for ApprovalRequestHandler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
str
|
The request to be handled. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The result of handling the request. |
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
EscalationRequestHandler
¶
Bases: RequestHandler
Handler that processes escalation requests.
This handler is responsible for handling requests related to escalations.
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
handle(request)
¶
Handles specific requests for EscalationRequestHandler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
str
|
The request to be handled. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The result of handling the request. |
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
RequestHandler
¶
Base class for handling requests in a chain of responsibility.
This class defines the interface for handling requests and allows for the creation of a chain of handlers. Each handler can process specific requests or pass them to the next handler in the chain.
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
__init__(successor=None)
¶
Initializes the handler with an optional successor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
successor
|
Optional[RequestHandler]
|
The next handler in the chain. |
None
|
Source code in src/design_patterns/behavioral/chain_of_responsibility.py
handle(request)
¶
Handles the request or passes it to the next handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
str
|
The request to be handled. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The result of the request. |