Understanding Design Patterns
What Are Design Patterns?
Design patterns are time-tested, reusable solutions to frequent challenges in software design. Think of them as blueprints which can be adapted and applied to resolve specific design issues in your coding projects. These aren’t one-size-fits-all, but rather guidelines to help accelerate the development process.
Why Design Patterns Matter:
Why Learn Design Patterns?
You might think, "I've been coding for years without knowing these patterns. Why start now?" Here's the thing: you may already be using patterns unknowingly. Being intentional about learning them offers several advantages:
Remember, even if you never use a particular pattern, the act of learning them enriches your design thinking and broadens your coding horizons.
Good Practices vs. Poor Practices with Design Patterns
“If all you have is a hammer, everything looks like a nail.”
While design patterns can be very useful, they can also be misused or overused.
Let's go through some common design patterns, their criticism, and provide Python examples.
Factory Pattern
Poor Use: Using Factory when the creation process is too simple.
领英推荐
class Button:
@staticmethod
def create_button(button_type):
return Button()
button = Button.create_button("simple") # Overcomplicating a simple creation.
Good Use: Using Factory to create UI elements that vary based on the operating system.
class Button:
@staticmethod
def create_button(os_type):
if os_type == "Windows":
return WindowsButton()
elif os_type == "Mac":
return MacButton()
raise ValueError("Invalid OS type")
class WindowsButton(Button):
def render(self):
return "Windows-style button"
class MacButton(Button):
def render(self):
return "Mac-style button"
button = Button.create_button("Windows")
print(button.render()) # Outputs: Windows-style button
Observer Pattern
Poor Use: Using Observer when there's only a single dependent.
class Price:
def __init__(self):
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def set_price(self, price):
self.price = price
for observer in self._observers:
observer.update(self)
class Display:
def update(self, subject):
print("New price:", subject.price)
# When you only have a single dependent, this is overkill.
price = Price()
display = Display()
price.add_observer(display)
price.set_price(100)
Good Use: Using Observer to update multiple displays or systems when stock prices change.
class Stock:
def __init__(self, symbol):
self._observers = []
self.symbol = symbol
self._price = 0
def add_observer(self, observer):
self._observers.append(observer)
def set_price(self, price):
self._price = price
for observer in self._observers:
observer.update(self)
@property
def price(self):
return self._price
class StockDisplay:
def update(self, stock):
print(f"New price for {stock.symbol}: {stock.price}")
class AlertSystem:
def update(self, stock):
if stock.price > 100:
print(f"Alert! {stock.symbol} price is very high!")
google = Stock("GOOGL")
display = StockDisplay()
alert = AlertSystem()
google.add_observer(display)
google.add_observer(alert)
google.set_price(101) # This will notify both the display and the alert system.
Remember, the decision to use a design pattern should not be based on its popularity, but rather on whether it genuinely fits the problem at hand. Often, simpler code without patterns is more readable and maintainable.
?? Join Us
Stay tuned with Product Development Playbook where we share insights and knowledge from our journey in product innovation.
??Resources