Chain of Responsibility Design Pattern in Python

class AbstractHandler:
'''Abstract Handler: inherited by all concrete handlers; throws a NotImplementedError if the concrete
handler does not define its own copy of processRequest() method.'''
def __init__(self, successor):
''''sets the next handler to local variable "_successor"'''
self._successor = successor
def handle(self, request):
'''invokes the processRequest() of the current handler; if request is handled, then processing of
next request begins; if request cannot be handled by the current handler, it is passed on to the
handle() method of the successor handler.'''
handled = self.processRequest(request)
if not handled:
self._successor.handle(request)
def processRequest(self, request):
'''throws a NotImplementedError if the concrete handler does not define its own copy of
processRequest() method.'''
raise NotImplementedError('Must provide implementation in subclass!')
class ConcreteHandlerOne(AbstractHandler):
'''Concrete Handler # 1: Inherits from the abstract handler; overrides the processRequest() method of the
AbstractHandler; has the handle() method by default, due to inheritance of the AbstractHandler'''
def processRequest(self, request):
'''Attempt to handle the request; return True if handled'''
if 0 < request <= 10:
print("This is {} handling request '{}'".format(self.__class__.__name__, request))
return True
class ConcreteHandlerTwo(AbstractHandler):
'''Concrete Handler # 2: Inherits from the abstract handler; overrides the processRequest() method of the
AbstractHandler; has the handle() method by default, due to inheritance of the AbstractHandler'''
def processRequest(self, request):
'''Attempt to handle the request; return True if handled'''
if 10 < request <= 20:
print("This is {} handling request '{}'".format(self.__class__.__name__, request))
return True
class DefaultHandler(AbstractHandler):
'''Default Handler: inherits from the abstract handler; overrides the processRequest() method of the
AbstractHandler; has the handle() method by default, due to inheritance of the AbstractHandler'''
def processRequest(self, request):
'''Provide an elegant message saying that this request has no handler. returns True to imply that
even this request has been handled.'''
print("This is {} telling you that request '{}' has no handler right now.".format(self.__class__.__name__, request))
return True
class Client:
'''Client: Uses handlers'''
def __init__(self):
'''Create the sequence of handlers that you want the requests to follow, and assign the sequence to
local variable "handle". Notice that the DefaultHandler, like all Handlers, needs to be provided
a successor, but since it is the last handler in line, we give it a successor "None".'''
self.handler = ConcreteHandlerOne(ConcreteHandlerTwo(DefaultHandler(None)))
def delegate(self, requests):
'''Iterates over requests and sends them, one by one, to handlers as per sequence of handlers defined above.'''
for request in requests:
self.handler.handle(request)
# Create a client object
clientOne = Client()
# Create requests to be processed.
requests = [6, 12, 24, 18]
# Send the requests one by one, to handlers as per sequence of handlers defined in the Client class.
clientOne.delegate(requests)
### OUTPUT ###
This is ConcreteHandlerOne handling request '6'
This is ConcreteHandlerTwo handling request '12'
This is DefaultHandler telling you that request '24' has no handler right now.
This is ConcreteHandlerTwo handling request '18'