The Chain of Responsibility Design Pattern in Python
The Chain of Responsibility design pattern is a behavioral pattern that allows a series of objects to handle a request by passing it along a dynamic chain of objects until the request is handled. This pattern decouples the sender of a request from the receiver, allowing the objects in the chain to be rearranged and modified dynamically.
In the Chain of Responsibility pattern, each object in the chain contains a reference to the next object. When a request is received, the first object in the chain attempts to handle it. If it is unable to do so, it passes the request along to the next object in the chain. This continues until the request is handled or the end of the chain is reached.
Here’s an example of how the Chain of Responsibility pattern could be implemented in Python:
class AbstractHandler:
def __init__(self, successor=None):
self._successor = successor
def handle(self, request):
handled = self._handle(request)
if not handled:
self._successor.handle(request)
def _handle(self, request):
raise NotImplementedError('Must provide implementation in subclass.')
class ConcreteHandler1(AbstractHandler):
def _handle(self, request):
if 0 < request <= 10:
print(f'Request {request} handled in handler 1')
return True
class ConcreteHandler2(AbstractHandler):
def _handle(self, request):
if 10 < request <= 20:
print(f'Request {request} handled in handler 2')
return True
class ConcreteHandler3(AbstractHandler):
def _handle(self, request):
if 20 < request <= 30:
print(f'Request {request} handled in handler 3')
return True
def main():
h1 = ConcreteHandler1()
h2 = ConcreteHandler2(h1)
h3 = ConcreteHandler3(h2)
requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
for request in requests:
h3.handle(request)
if __name__ == '__main__':
main()
In this example, the AbstractHandler
class defines the basic structure for handling requests and contains a reference to the next object in the chain. The handle
method attempts to handle the request and if it is unable to do so, it passes the request along to the next object in the chain. The _handle
method must be implemented by subclasses to handle specific requests.
The ConcreteHandler1
, ConcreteHandler2
, and ConcreteHandler3
classes are concrete implementations of the AbstractHandler
class and each handle different ranges of requests. In the main
function, an instance of each concrete handler is created and linked together to form the chain. Finally, a series of requests is sent through the chain and handled by the appropriate handler.
In conclusion, the Chain of Responsibility pattern is a useful pattern for handling requests in a flexible and dynamic way. By decoupling the sender of a request from the receiver, it allows for the objects in the chain to be rearranged and modified dynamically, making it well-suited for complex and evolving systems.