Slide 1

Slide 1 text

DESIGN PATTERNS IN PYTHON Ellen König, SoundCloud @ellen_koenig

Slide 2

Slide 2 text

THE PATTERN: SINGLETON ➤ Solves an abstract problem: You want to ensure that only one instance of an object can be created ➤ Provides a solution: Private constructors & a single instance as a private class attribute ➤ Say, you want to to limit access to a hardware resource such as a printer that only exists once in the office ➤ or to manage a complex configuration class only once STARTING WITH AN EXAMPLE

Slide 3

Slide 3 text

THEORY

Slide 4

Slide 4 text

A PATTERN IS… An adaptable, reusable solution for a common problem in the design and architecture of (object-oriented) software.

Slide 5

Slide 5 text

A PATTERN IS NOT… An algorithm, a copy & paste snippet, a framework or a library

Slide 6

Slide 6 text

A PATTERN DESCRIBES… Relationships between objects or components in a general solution for a common problem, which can (and must) be adapted into a concrete implementation

Slide 7

Slide 7 text

ELEMENTS OF A PATTERN ➤ A problem that the pattern solves (generalized use case) ➤ Components & structure of the solution ➤ Implementation

Slide 8

Slide 8 text

SOME USEFUL PATTERNS

Slide 9

Slide 9 text

SINGLETON ➤ Type: Pattern for creating objects ➤ Solved problem: You want to ensure that only one instance of an object can be created ➤ Example: To limit access to a hardware resource such as a printer, or to manage complex configuration class ➤ Solution: Private constructors & a single instance as a private class attribute

Slide 10

Slide 10 text

SINGLETON: IMPLEMENTATION IN PYTHON #  Singleton  provider  using  a  module  (file  a.py)   def  __generate_instance():          return  VeryExpensiveObject()   INSTANCE  =  __generate_instance() #  Singleton  user  (file  b.py)   from  a  import  INSTANCE   INSTANCE.do_something()

Slide 11

Slide 11 text

FACTORY ➤ Type: Pattern for creating objects ➤ Solved problem: Creating objects of related types by calling the same factory method. ➤ Example: Drivers for different SQL databases (SQLite, MySQL, Oracle, Postgres, …) that all adhere to the same interface ➤ Solution: Concrete „product“ objects inherit from a product base type/interface & the factory returns objects of the base product type

Slide 12

Slide 12 text

FACTORY: IMPLEMENTATION IN PYTHON #  Factory  definition   class  Convoy(object):          def  __init__(self,  car_class=VWCar,  number=5):                  self.convoy  =  [car_class()  for  i  in  range(0,  number)]   #  Factory  usage   c  =  Convoy()   c1  =  Convoy(car_class=BMWCar)

Slide 13

Slide 13 text

STRATEGY ➤ Type: Pattern for defining object behavior ➤ Solved problem: Providing alternative implementations („strategies“/algorithms) for a behavior ➤ Examples: ➤ Different ways to sort a collection ➤ different formats to encode data (JSON, binary, XML, CSV, …) ➤ Solution: All strategies implement a „Strategy“ interface, the context class that uses the different strategies uses the „Strategy“ interface

Slide 14

Slide 14 text

STRATEGY: IMPLEMENTATION IN PYTHON #  Strategy  definition  using  first  class  functions   def  encode_binary(content):   pass   def  encode_json(content):   pass   ENCODERS  =  {'binary':  encode_binary,  'json':  encode_json} #  Strategy  usage   e  =  ENCODERS['binary'](content)

Slide 15

Slide 15 text

PROXY ➤ Type: Pattern for structuring (static) object relationships ➤ Solved problem: Controlling access to a component by hiding it from the client ➤ Example: Limiting access to a web service provided for two different client companies with different contracts each ➤ Solution: The proxy is put in between the client and the provider

Slide 16

Slide 16 text

PROXY: IMPLEMENTATION IN PYTHON #  Proxy  definition   class  ProtectedServer(object):   def  restricted_method1(…):   pass   def  restricted_method2(…):   pass   #  Proxy  usage   client_a  =  ApiForCompanyA()   client_a.available_method()   client_b  =  ApiForCompanyB()   client_b.available_method() class  ApiForCompanyA(object):   def  __init__(self):   self.server  =  ProtectedServer()   def  available_method(self,  …):   self.server.protected_method1()   class  ApiForCompanyB(object):     ….

Slide 17

Slide 17 text

OBSERVER ➤ Type: Pattern for defining object behavior ➤ Solved problem: Ensuring that two (or more) objects stay in sync, i.e. object B will be updated whenever object A changes ➤ Example: Updating the user interface whenever the backend changes ➤ Solution: Publish-subscribe mechanism: The observable object will inform all its observer objects whenever it changes by calling a “notify” method defined in the Observer interface

Slide 18

Slide 18 text

OBSERVER: IMPLEMENTATION IN PYTHON #  Registering  a  concrete  observer   observable  =  ObservableClass()   observable.add_observer(lambda  x:  print  "An  observer") #  …  class  Observable  continued   def  notify(self):   for  observer  in  self.__observers:   #  call  the  observer  function   observer(self) #  Observable  definition   class  Observable(object):   def  __init__(self):                    self.__observers  =  []   def  add_observer(self,  observer):   self.__observers.append(observer)

Slide 19

Slide 19 text

WRAP UP

Slide 20

Slide 20 text

SUMMARY ➤ Patterns describe generalised relationships between objects that solve common problems in the architecture and design of complex software systems ➤ Patterns are commonly used in (and described for) OOP languages like Java and make heavy use of interfaces ➤ Many patterns can be implemented in simpler ways in Python using language features such as ➤ Functions as first class citizens ➤ Callables ➤ Modules ➤ Patterns are frequently used in the source code of frameworks (e.g. Django, SQLAlchemy) and help understand and use them

Slide 21

Slide 21 text

PRACTICE: WHICH PATTERNS DO YOU RECOGNIZE HERE? class  PaymentProxy(object):          def  __init__(self,  payment_cls=PaymentProcessor,  max_value=10,  rules=None):                  self.__payment_processor  =  payment_cls()                  self.__max_value  =  max_value                  self.__rules  =  rules  or  []          def  pay(self,  amt):                  for  r  in  rules:                          if  not  r[0](amt):  raise  r[1]                  if  amt>self.__max_value:                          raise  Error                  return  self.__payment_processor.pay(amt)   rules  =  [(lambda  x:  x<-­‐1,  "Price  can't  be  negative"),  (lambda  x:  x>100,  "Price  can't  be  more  than  100)")   a  =  PaymentProxy(rules=rules)   a.pay(9)   a  =  PaymentProxy(payment_cls=VisaProcessor,  max_value=666)   a.pay(100)  

Slide 22

Slide 22 text

PRACTICE ➤ In pairs or by yourself, find your own use case for each pattern ➤ Singleton ➤ Factory ➤ Strategy ➤ Proxy ➤ Observer ➤ Optional: Pick one or two of your use cases and implement a solution using the pattern in Python

Slide 23

Slide 23 text

SOURCES ➤Pattern descriptions: Book: M. Geirhos - Entwurfsmuster (2015) and Wikipedia ➤Python code sample credits: Tasos Vogiatzoglou, Lieferheld

Slide 24

Slide 24 text

IMAGE CREDITS ➤ Title: https://en.wikipedia.org/wiki/Adinkra_symbols#/media/ File:Adinkra_1825.jpg ➤ Slide 2: https://en.wikipedia.org/wiki/Huichol_people#/media/ File:Arte_del_Pueblo_Huichol.jpg ➤ Slide 3: https://upload.wikimedia.org/wikipedia/commons/b/b6/ Olazu_Mola.JPG ➤ Slide 4: http://www.publicdomainpictures.net/view-image.php? image=110833&picture=turkish-carpet-kaleidoscope ➤ Slide 5: https://pixabay.com/static/uploads/photo/2015/08/27/20/07/ zentangle-911068_960_720.jpg ➤ Slide 5 - MVC pattern: https://commons.wikimedia.org/wiki/ File:ModelViewControllerDiagram_es.svg ➤ Slide 6: Keynote template stock image ➤ Slide 7: https://en.wikipedia.org/wiki/Islamic_geometric_patterns#/media/ File:Alhambra-p3-closeup.jpg ➤ Slide 8 - Singleton UML: By HenrikKronborgPedersen - Drawing it, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=22015740 ➤ Slide 10 - Factory UML: https://commons.wikimedia.org/wiki/ File:Factory_Method_UML_class_diagram.png ➤ Slide 12 - Strategy UML: https://commons.wikimedia.org/wiki/ File:StrategyPatternClassDiagram.svg ➤ Slide 14 - Proxy UML: https://commons.wikimedia.org/wiki/ File:Proxy_pattern_diagram.svg ➤ Slide 16 - Observer UML: https://commons.wikimedia.org/wiki/ File:Observer.svg ➤ Slide 19 - Wrap up: http://www.123freevectors.com/seamless-flower-pattern/ ➤ Sources: https://en.wikipedia.org/wiki/Ewe_people#/media/ File:Ewe_kente_stripes,_Ghana.jpg

Slide 25

Slide 25 text

LICENSE Creative Commons Attribution-Share Alike 3.0