Design Pattern Quick Reference
Total Page:16
File Type:pdf, Size:1020Kb
APPENDIX A Design Pattern Quick Reference Quick Checks for the Code 1. Singleton Pattern 2. Prototype Pattern 3. Factory Pattern 4. Builder Pattern 5. Adapter Pattern 6. Decorator Pattern 7. Facade Pattern 8. Proxy Pattern 9. Chain of Responsibility Pattern 10. Composite 11. Command Pattern 12. Interpreter Pattern 13. Iterator Pattern 14. Observer Pattern 15. State Pattern 16. Strategy Pattern 327 © Wessel Badenhorst 2017 W. Badenhorst, Practical Python Design Patterns, https://doi.org/10.1007/978-1-4842-2680-3 APPENDIX A DESIGN PaTTERN QUICK REFERENCE 17. Template Method Pattern 18. Visitor Pattern 19. Model–View–Controller Pattern 20. Publisher–Subscriber Pattern Singleton singleton.py class SingletonObject(object): class __SingletonObject(): def __init__(self): self.val = None def __str__(self): return "{0!r} {1}".format(self, self.val) # the rest of the class definition will follow here, as per the previous logging script instance = None def __new__(cls): if not SingletonObject.instance: SingletonObject.instance = SingletonObject.__SingletonObject() return SingletonObject.instance def __getattr__(self, name): return getattr(self.instance, name) def __setattr__(self, name): return setattr(self.instance, name) 328 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Prototype prototype_1.py from abc import ABCMeta, abstractmethod class Prototype(metaclass=ABCMeta): @abstractmethod def clone(self): pass concrete.py from prototype_1 import Prototype from copy import deepcopy class Concrete(Prototype): def clone(self): return deepcopy(self) Factory factory.py import abc class AbstractFactory(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def make_object(self): return class ConcreteFactory(AbstractFactory): def make_object(self): # do something return ConcreteClass() 329 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Builder form_builder.py from abc import ABCMeta, abstractmethod class Director(object, metaclass=ABCMeta): def __init__(self): self._builder = None @abstractmethod def construct(self): pass def get_constructed_object(self): return self._builder.constructed_object class Builder(object, metaclass=ABCMeta): def __init__(self, constructed_object): self.constructed_object = constructed_object class Product(object): def __init__(self): pass def __repr__(self): pass class ConcreteBuilder(Builder): pass class ConcreteDirector(Director): pass 330 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Adapter third_party.py class WhatIHave(object): def provided_function_1(self): pass def provided_function_2(self): pass class WhatIWant(object): def required_function(): pass adapter.py from third_party import WhatIHave class ObjectAdapter(object): def __init__(self, what_i_have): self.what_i_have = what_i_have def required_function(self): return self.what_i_have.provided_function_1() def __getattr__(self, attr): # Everything else is handled by the wrapped object return getattr(self.what_i_have, attr) Decorator decorator.py from functools import wraps def dummy_decorator(f): @wraps(f) def wrap_f(): print("Function to be decorated: ", f.__name__) print("Nested wrapping function: ", wrap_f.__name__) return f() return wrap_f 331 APPENDIX A DESIGN PaTTERN QUICK REFERENCE @dummy_decorator def do_nothing(): print("Inside do_nothing") if __name__ == "__main__": print("Wrapped function: ",do_nothing.__name__) do_nothing() Facade simple_ facade.py class Invoice: def __init__(self, customer): pass class Customer: Altered customer class to try to fetch a customer on init or creates a new one def __init__(self, customer_id): pass class Item: # Altered item class to try to fetch an item on init or creates a new one def __init__(self, item_barcode): pass class Facade: @staticmethod def make_invoice(customer): return Invoice(customer) @staticmethod def make_customer(customer_id): return Customer(customer_id) @staticmethod def make_item(item_barcode): return Item(item_barcode) # ... 332 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Proxy proxy.py import time class RawClass(object): def func(self, n): return f(n) def memoize(fn): __cache = {} def memoized(*args): key = (fn.__name__, args) if key in __cache: return __cache[key] __cache[key] = fn(*args) return __cache[key] return memoized class ClassProxy(object): def __init__(self, target): self.target = target func = getattr(self.target, 'func') setattr(self.target, 'func', memoize(func)) def __getattr__(self, name): return getattr(self.target, name) 333 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Chain of Responsibility chain_of_responsibility.py class EndHandler(object): def __init__(self): pass def handle_request(self, request): pass class Handler1(object): def __init__(self): self.next_handler = EndHandler() def handle_request(self, request): self.next_handler.handle_request(request) def main(request): concrete_handler = Handler1() concrete_handler.handle_request(request) if __name__ == "__main__": # from the command line we can define some request main(request) Alternative chain_of_responsibility_alt.py class Dispatcher(object): def __init__(self, handlers=[]): self.handlers = handlers def handle_request(self, request): for handler in self.handlers: request = handler(request) return request 334 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Command command.py class Command: def __init__(self, receiver, text): self.receiver = receiver self.text = text def execute(self): self.receiver.print_message(self.text) class Receiver(object): def print_message(self, text): print("Message received: {}".format(text)) class Invoker(object): def __init__(self): self.commands = [] def add_command(self, command): self.commands.append(command) def run(self): for command in self.commands: command.execute() if __name__ == "__main__": receiver = Receiver() command1 = Command(receiver, "Execute Command 1") command2 = Command(receiver, "Execute Command 2") invoker = Invoker() invoker.add_command(command1) invoker.add_command(command2) invoker.run() 335 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Composite composite.py class Leaf(object): def __init__(self, *args, **kwargs): pass def component_function(self): print("Leaf") class Composite(object): def __init__(self, *args, **kwargs): self.children = [] def component_function(self): for child in children: child.component_function() def add(self, child): self.children.append(child) def remove(self, child): self.children.remove(child) Interpreter interpreter.py class NonTerminal(object): def __init__(self, expression): self.expression = expression def interpret(self): self.expression.interpret() class Terminal(object): def interpret(self): pass 336 APPENDIX A DESIGN PaTTERN QUICK REFERENCE Iterator classic_iterator.py import abc class Iterator(metaclass=abc.ABCMeta): @abc.abstractmethod def has_next(self): pass @abc.abstractmethod def next(self): pass class Container(metaclass=abc.ABCMeta): @abc.abstractmethod def getIterator(self): pass class MyListIterator(Iterator): def __init__(self, my_list): self.index = 0 self.list = my_list.list def has_next(self): return self.index < len(self.list) def next(self): self.index += 1 return self.list[self.index - 1] class MyList(Container): def __init__(self, *args): self.list = list(args) def getIterator(self): return MyListIterator(self) 337 APPENDIX A DESIGN PaTTERN QUICK REFERENCE if __name__ == "__main__": my_list = MyList(1, 2, 3, 4, 5, 6) my_iterator = my_list.getIterator() while my_iterator.has_next(): print(my_iterator.next()) Alternative iterator_alt.py for element in collection: do_something(element) Observer observer.py class ConcreteObserver(object): def update(self, observed): print("Observing: {}".format(observed)) class Observable(object): def __init__(self): self.callbacks = set() self.changed = False def register(self, callback): self.callbacks.add(callback) def unregister(self, callback): self.callbacks.discard(callback) def unregister_all(self): self.callbacks = set() 338 APPENDIX A DESIGN PaTTERN QUICK REFERENCE def poll_for_change(self): if self.changed: self.update_all def update_all(self): for callback in self.callbacks: callback(self) State state.py class State(object): pass class ConcreteState1(State): def __init__(self, state_machine): self.state_machine = state_machine def switch_state(self): self.state_machine.state = self.state_machine.state2 class ConcreteState2(State): def __init__(self, state_machine): self.state_machine = state_machine def switch_state(self): self.state_machine.state = self.state_machine.state1 class StateMachine(object): def __init__(self): self.state1 = ConcreteState1(self) self.state2 = ConcreteState2(self) self.state = self.state1 def switch(self): self.state.switch_state() 339 APPENDIX A DESIGN PaTTERN QUICK REFERENCE def __str__(self): return str(self.state) def main(): state_machine = StateMachine() print(state_machine) state_machine.switch() print(state_machine) if __name__ == "__main__": main() Strategy strategy.py def executor(arg1, arg2, func=None): if func is None: return "Strategy not implemented..." return func(arg1, arg2) def strategy_1(arg1, arg2): return f_1(arg1, arg2) def strategy_2(arg1, arg2): return f_2(arg1, arg2) Template Method template_method.py import abc class TemplateAbstractBaseClass(metaclass=abc.ABCMeta): def template_method(self): self._step_1() self._step_2() self._step_n() 340 APPENDIX A DESIGN PaTTERN QUICK REFERENCE @abc.abstractmethod def _step_1(self): pass @abc.abstractmethod def _step_2(self): pass @abc.abstractmethod def _step_3(self): pass class ConcreteImplementationClass(TemplateAbstractBaseClass): def _step_1(self): pass def _step_2(self): pass def _step_3(self):