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
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
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
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
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
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
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
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)
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