Creational
Creational design patterns are used to
- Create objects effectively
- Add flexibility to software design
Many designs start by using Factory Method (less complicated and more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complicated).
Factory Pattern
-
- Object Creation without Exposing Concrete Classes:
- Factories provide a centralized way to create objects, allowing for better encapsulation and abstraction.
- Dynamic Object Creation:
- Factories are useful when the exact class of the object to be created may vary at runtime based on certain conditions or configurations.
- Factories can select the appropriate subclass or implementation to create based on these conditions.
- Polymorphic Object Creation:
- Allowing clients to create objects without knowing the specific subclass or implementation being instantiated.
- This promotes loose coupling and simplifies client code.
- Difference to Dependency Injection:
- When using a factory your code is still actually responsible for creating objects. By DI you outsource that responsibility to another class or a framework, which is separate from your code.
- Object Creation without Exposing Concrete Classes:
class Burger:
def __init__(self, ingredients):
self.ingredients = ingredients
def print(self):
print(self.ingredients)
class BurgerFactory:
def createCheeseBurger(self):
ingredients = ["bun", "cheese", "beef-patty"]
return Burger(ingredients)
def createDeluxeCheeseBurger(self):
ingredients = ["bun", "tomatoe", "lettuce", "cheese", "beef-patty"]
return Burger(ingredients)
def createVeganBurger(self):
ingredients = ["bun", "special-sauce", "veggie-patty"]
return Burger(ingredients)
burgerFactory = BurgerFactory()
burgerFactory.createCheeseBurger().print()
burgerFactory.createDeluxeCheeseBurger().print()
burgerFactory.createVeganBurger().print()
Output
['bun', 'cheese', 'beef-patty']
['bun', 'tomatoe', 'lettuce', 'cheese', 'beef-patty']
['bun', 'special-sauce', 'veggie-patty']
Builder Pattern
class Burger:
def __init__(self):
self.buns = None
self.patty = None
self.cheese = None
def setBuns(self, bunStyle):
self.buns = bunStyle
def setPatty(self, pattyStyle):
self.patty = pattyStyle
def setCheese(self, cheeseStyle):
self.cheese = cheeseStyle
class BurgerBuilder:
def __init__(self):
self.burger = Burger()
def addBuns(self, bunStyle):
self.burger.setBuns(bunStyle)
return self
def addPatty(self, pattyStyle):
self.burger.setPatty(pattyStyle)
return self
def addCheese(self, cheeseStyle):
self.burger.setCheese(cheeseStyle)
return self
def build(self):
return self.burger
burger = BurgerBuilder() \
.addBuns("sesame") \
.addPatty("fish-patty") \
.addCheese("swiss cheese") \
.build()
Singleton
Singleton Pattern is considered unpythonic
https://www.youtube.com/watch?v=Rm4JP7JfsKY&t=634s
Why it is bad:
- If you inherit from it, you can get multiple instances, which shouldn't be allowed.
- Testing code is hard with singleton because you cannot create multiple fresh instances for testing
- Does not work well with multi threaded applications because raise condition of
class ApplicationState:
instance = None
def __init__(self):
self.isLoggedIn = False
@staticmethod
def getAppState():
if not ApplicationState.instance:
ApplicationState.instance = ApplicationState()
return ApplicationState.instance
appState1 = ApplicationState.getAppState()
print(appState1.isLoggedIn)
appState2 = ApplicationState.getAppState()
appState1.isLoggedIn = True
print(appState1.isLoggedIn)
print(appState2.isLoggedIn)
>> False
>> True
>> True
No Comments