Welcome to our comprehensive guide on Design Patterns! These are reusable solutions to common problems that software developers encounter while designing applications. Let's dive in and learn about some popular ones.
Design Patterns are not code, but rather general design strategies that help developers solve common problems in a more efficient, maintainable, and scalable way. They provide a blueprint for organizing and implementing software structures.
Creational patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.
The Singleton pattern ensures that only one instance of a class exists at any given time. This can be useful for managing resources that should be accessed globally.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
def foo(self):
print("Singleton instance")
singleton = Singleton()
another_singleton = Singleton()
print(id(singleton) == id(another_singleton)) # Output: TrueQuestion: What does the Singleton pattern ensure?
A: Multiple instances of a class B: Only one instance of a class C: No instances of a class
Correct: B Explanation: The Singleton pattern ensures that only one instance of a class exists at any given time.
Structural patterns focus on object composition to form larger structures and solve problems related to object composition.
The Decorator pattern allows you to add new behavior to an existing object without modifying its structure. This is useful for dynamic and flexible object customization.
class Beverage:
def cost(self):
return 0
class Espresso(Beverage):
def cost(self):
return 1.99
class Soy(Beverage):
def cost(self):
return 0.75
class Mocha(Beverage):
def cost(self):
return 2.59
class CondimentDecorator(Beverage):
def __init__(self, beverage):
self.beverage = beverage
def cost(self):
return self.beverage.cost()
def __getattr__(self, name):
return getattr(self.beverage, name)
class SoyLatte(CondimentDecorator):
def cost(self):
return self.Soy.cost() + 0.75
class MochaLatte(CondimentDecorator):
def cost(self):
return self.Mocha.cost() + 0.75
espresso = Espresso()
soy_latte = Soy(SoyLatte(espresso))
mocha_latte = Mocha(MochaLatte(espresso))
print(f"Espresso: ${espresso.cost()}")
print(f"Soy Latte: ${soy_latte.cost()}")
print(f"Mocha Latte: ${mocha_latte.cost()}")Question: What is the purpose of the Decorator pattern?
A: To modify the structure of an existing object B: To add new behavior to an existing object without modifying its structure C: To create new objects
Correct: B Explanation: The Decorator pattern allows you to add new behavior to an existing object without modifying its structure.