본문 바로가기
Practical Python Design Patterns

Design Pattern Quick Reference

by 자동매매 2023. 3. 29.

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

  1. Template Method Pattern
  2. Visitor Pattern
  3. Model View Controller Pattern
  4. 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): pass

Visitor

visitor.py import abc

class Visitable(object):

def accept(self, visitor):

visitor.visit(self)

class CompositeVisitable(Visitable): def __init__(self, iterable): self.iterable = iterable

def accept(self, visitor):

for element in self.iterable: element.accept(visitor)

visitor.visit(self)

341
APPENDIX A DESIGN PATTERN QUICK REFERENCE

class AbstractVisitor(object):

__metaclass__ = abc.ABCMeta

@abc.abstractmethod

def visit(self, element):

raise NotImplementedError("A visitor need to define a visit method")

class ConcreteVisitable(Visitable):

def __init__(self):

pass

class ConcreteVisitor(AbstractVisitor):

def visit(self, element):

pass

Model–View–Controller

mvc.py

import sys

class GenericController(object):

def __init__(self):

self.model = GenericModel() self.view = GenericView()

def handle(self, request):

data = self.model.get_data(request) self.view.generate_response(data)

class GenericModel(object):

def __init__(self):

pass

def get_data(self, request):

return {’request’: request}

342
APPENDIX A DESIGN PATTERN QUICK REFERENCE

class GenericView(object): def __init__(self):

pass

def generate_response(self, data):

print(data)

def main(name):

request_handler = GenericController() request_handler.handle(name)

if __name__ == "__main__":

main(sys.argv[1])

Publisher–Subscriber

publish_subscribe.py

class Message(object):

def __init__(self):

self.payload = None self.topic = "all"

class Subscriber(object):

def __init__(self, dispatcher, topic):

dispatcher.subscribe(self, topic)

def process(self, message):

print("Message: {}".format(message.payload))

class Publisher(object):

def __init__(self, dispatcher):

self.dispatcher = dispatcher

def publish(self, message):

self.dispatcher.send(message)

343
APPENDIX A DESIGN PATTERN QUICK REFERENCE

class Dispatcher(object):

def __init__(self):

self.topic_subscribers = dict()

def subscribe(self, subscriber, topic):

self.topic_subscribers.setdefault(topic, set()).add(subscriber)

def unsubscribe(self, subscriber, topic):

self.topic_subscribers.setdefault(topic, set()).discard(subscriber)

def unsubscribe_all(self, topic):

self.subscribers = self.topic_subscribers[topic] = set()

def send(self, message):

for subscriber in self.topic_subscribers[message.topic]:

subscriber.process(message)

Final Words

Well done! You have learned many useful patterns. I hope that you will continue to practice and become a better programmer every day.

Thank you for going on this journey with me. Goodbye and good luck.

344

'Practical Python Design Patterns' 카테고리의 다른 글

PUBLISH–SUBSCRIBE PATTERN  (0) 2023.03.29
Model-View-Controller Pattern  (0) 2023.03.29
Visitor Pattern  (0) 2023.03.29
Template Method Pattern  (0) 2023.03.29
Strategy Pattern  (0) 2023.03.29

댓글