There are many examples of the implementation of the Chain of Responsibility design pattern in Python out there, some adding some new bits, some bearing some baggage and a few wishful ones. However, I recently found myself in need of a simpler and adaptable example.
Below is the python version of the C++ example code given in the book Design Patterns: Elements of Reusable Object-Oriented Software. I hope you find it useful in your own projects.
The important part is the HelpHandler class, which manages the successors in the chain
class HelpHandler (object): def __init__(self, successor=0, topic=NO_HELP_TOPIC): self._successor = successor self._topic = topic def HasHelp(self): return self._topic != NO_HELP_TOPIC; def HandleHelp(self): if self._successor != 0: self._successor.HandleHelp() def SetHandler(self,h,t): self._successor = h self._h = t
In our case we have a Widget class that inherits from HelpHandler:
class Widget(HelpHandler): def __init__(self, w, t): super(Widget,self).__init__(w,t)
Which we will use to build two sub-classes (Dialog and Button)
class Button(Widget): def __init__(self, d, t): super(Button,self).__init__(d,t) def HandleHelp(self): if self.HasHelp(): print "Button Help" else: return super(Button, self).HandleHelp() class Dialog(Widget): def __init__(self, h, t): super(Dialog,self).__init__(h,t) self.SetHandler(h,t) def HandleHelp(self): if self.HasHelp(): print "Dialog Help" else: return super(Dialog, self).HandleHelp()
In the root of our chain we will have an Application Class that will handle the request for help:
class Application(HelpHandler): def __init__(self, t): super(Application,self).__init__(0,t) def HandleHelp(self): print "Application Help"
Creating a chain is as easy as creating an Application, Dialog, and Button and invoking the help anywhere in the chain. Like so:
PRINT_TOPIC = 1 PAPER_ORIENTATION = 2 APPLICATION_TOPIC = 3 NO_HELP_TOPIC = -1 application = Application(APPLICATION_TOPIC) dialog = Dialog(application, PRINT_TOPIC) button = Button(dialog, NO_HELP_TOPIC) # invoking help in the chain button.HandleHelp()
For your full enjoyment here is the complete implementation: