Creational
Creational design patterns are used to
- Create objects effectively
- Add flexibility to software design
.
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.
- 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
Use modules over singleton
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