Design patterns are reusable solutions to common problems that arise during software development. They provide a way to create a well-designed and maintainable code structure. Here are some commonly used design patterns in Python:
1. Singleton Pattern:
- Ensures that a class has only one instance and provides a global point of access to it.
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
2. Factory Pattern:
- Defines an interface for creating an object but leaves the choice of its type to the subclasses.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class AnimalFactory:
def create_animal(self, animal_type):
if animal_type == "Dog":
return Dog()
elif animal_type == "Cat":
return Cat()
3. Observer Pattern:
- Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.
class Subject:
def __init__(self):
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def remove_observer(self, observer):
self._observers.remove(observer)
def notify_observers(self, data):
for observer in self._observers:
observer.update(data)
class Observer:
def update(self, data):
pass
4. Strategy Pattern:
- Defines a family of algorithms, encapsulates each algorithm, and makes them interchangeable.
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} using credit card.")
class PayPalPayment(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} using PayPal.")
class ShoppingCart:
def __init__(self, payment_strategy):
self._payment_strategy = payment_strategy
def checkout(self, amount):
self._payment_strategy.pay(amount)
5. Decorator Pattern:
- Attaches additional responsibilities to an object dynamically.
class Coffee:
def cost(self):
return 5
class MilkDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost() + 2
6. Command Pattern:
- Encapsulates a request as an object, thereby allowing for parameterization of clients with different requests, queuing of requests, and logging of the parameters.
from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
class Light:
def turn_on(self):
print("Light is ON")
def turn_off(self):
print("Light is OFF")
class TurnOnCommand(Command):
def __init__(self, light):
self._light = light
def execute(self):
self._light.turn_on()
class TurnOffCommand(Command):
def __init__(self, light):
self._light = light
def execute(self):
self._light.turn_off()
These are just a few examples of design patterns. Python, being a versatile language, allows you to implement various design patterns, adapting them to your specific needs. Understanding and applying design patterns can lead to more flexible, maintainable, and scalable code.