0
0
LldConceptBeginner · 3 min read

Chain of Responsibility Pattern: Definition, Example, and Use Cases

The Chain of Responsibility pattern lets multiple objects handle a request by passing it along a chain until one object processes it. This avoids coupling the sender of a request to its receiver and allows dynamic handling of requests.
⚙️

How It Works

Imagine you have a line of people, each with a different skill. When a question is asked, the first person tries to answer it. If they can't, they pass the question to the next person, and so on, until someone answers or the line ends.

In software, the Chain of Responsibility pattern works the same way. A request is sent to the first handler object. If it can handle the request, it does so. If not, it passes the request to the next handler in the chain. This continues until the request is handled or no handlers remain.

This pattern helps separate the sender of a request from its receivers, making the system flexible and easier to extend with new handlers without changing existing code.

💻

Example

This example shows a simple chain of handlers that process support tickets based on their priority level.

python
class Handler:
    def __init__(self, successor=None):
        self.successor = successor

    def handle(self, request):
        handled = self.process_request(request)
        if not handled and self.successor:
            self.successor.handle(request)

    def process_request(self, request):
        raise NotImplementedError("Must provide implementation in subclass")

class LowPriorityHandler(Handler):
    def process_request(self, request):
        if request['priority'] == 'low':
            print(f"LowPriorityHandler handled request: {request['content']}")
            return True
        return False

class MediumPriorityHandler(Handler):
    def process_request(self, request):
        if request['priority'] == 'medium':
            print(f"MediumPriorityHandler handled request: {request['content']}")
            return True
        return False

class HighPriorityHandler(Handler):
    def process_request(self, request):
        if request['priority'] == 'high':
            print(f"HighPriorityHandler handled request: {request['content']}")
            return True
        return False

# Setup chain: low -> medium -> high
handler_chain = LowPriorityHandler(MediumPriorityHandler(HighPriorityHandler()))

# Requests with different priorities
requests = [
    {'priority': 'low', 'content': 'Password reset'},
    {'priority': 'medium', 'content': 'Software installation'},
    {'priority': 'high', 'content': 'System outage'},
    {'priority': 'urgent', 'content': 'Data breach'}
]

for req in requests:
    handler_chain.handle(req)
Output
LowPriorityHandler handled request: Password reset MediumPriorityHandler handled request: Software installation HighPriorityHandler handled request: System outage
🎯

When to Use

Use the Chain of Responsibility pattern when you want to avoid coupling the sender of a request to its receiver, and when multiple objects can handle a request but the handler is not known in advance.

It is useful when you want to add or change handlers dynamically without modifying the sender or other handlers.

Real-world examples include:

  • Event handling systems where events pass through multiple listeners
  • Logging frameworks with multiple log levels
  • Technical support systems routing tickets based on priority or type
  • Middleware pipelines in web servers

Key Points

  • Decouples sender and receiver by passing requests along a chain.
  • Each handler decides to process or forward the request.
  • Supports dynamic and flexible request processing.
  • Easy to add new handlers without changing existing code.
  • Can simplify complex conditional logic.

Key Takeaways

Chain of Responsibility passes requests along a chain until handled.
It decouples sender and receiver, improving flexibility.
Handlers decide independently whether to process or forward requests.
Useful for dynamic, extensible request processing systems.
Simplifies complex conditional logic by distributing responsibility.