Python26 min read

Python Design Patterns

Understand common design patterns so you can structure code cleanly, avoid messy spaghetti logic, and build scalable systems like real applications.

David Miller
August 27, 2025
9.8k207

A design pattern is a proven solution to a common coding problem.

        Important:
        Patterns are not “rules”. They are tools.
        Use a pattern only when it makes the code simpler and clearer.
        
        ## When patterns help most
        
        - when code is growing
        - when many developers work together
        - when you need flexibility and extension
        - when you want cleaner architecture
        
        ## 1) Singleton Pattern (one instance only)
        
        Purpose:
        - ensure only one object exists (like a DB connection manager)
        
        ```python
        class Database:
            _instance = None
        
            def __new__(cls):
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                return cls._instance
        
        db1 = Database()
        db2 = Database()
        print(db1 is db2)  # True
        ```
        
        Benefit:
        - shared global state safely (but use carefully)
        
        ## 2) Factory Pattern (create objects based on input)
        
        Purpose:
        - create different objects without repeating if/else everywhere
        
        ```python
        class Dog:
            def speak(self):
                return "Woof!"
        
        class Cat:
            def speak(self):
                return "Meow!"
        
        class AnimalFactory:
            @staticmethod
            def create(animal_type):
                if animal_type == "dog":
                    return Dog()
                if animal_type == "cat":
                    return Cat()
                raise ValueError("Unknown animal")
        
        animal = AnimalFactory.create("dog")
        print(animal.speak())
        ```
        
        Benefit:
        - easy to add new types later
        
        ## 3) Observer Pattern (notify subscribers)
        
        Purpose:
        - when many parts need updates after one change
        Examples:
        - UI updates
        - notifications
        - event systems
        
        ```python
        class Subject:
            def __init__(self):
                self._observers = []
        
            def attach(self, observer):
                self._observers.append(observer)
        
            def notify(self, message):
                for obs in self._observers:
                    obs.update(message)
        
        class Observer:
            def __init__(self, name):
                self.name = name
        
            def update(self, message):
                print(f"{self.name} received: {message}")
        
        subject = Subject()
        subject.attach(Observer("User1"))
        subject.attach(Observer("User2"))
        subject.notify("New update!")
        ```
        
        Benefit:
        - loose coupling (components don’t directly depend on each other)
        
        ## 4) Strategy Pattern (swap behavior at runtime)
        
        Purpose:
        - choose an algorithm/behavior dynamically
        Example:
        - multiple payment methods
        
        ```python
        class CreditCard:
            def pay(self, amount):
                print(f"Paid ${amount} with credit card")
        
        class PayPal:
            def pay(self, amount):
                print(f"Paid ${amount} with PayPal")
        
        class Cart:
            def __init__(self, strategy):
                self.strategy = strategy
        
            def checkout(self, amount):
                self.strategy.pay(amount)
        
        cart = Cart(CreditCard())
        cart.checkout(100)
        
        cart = Cart(PayPal())
        cart.checkout(50)
        ```
        
        Benefit:
        - no big if/else inside your checkout logic
        
        ## Graph: how patterns reduce complexity
        
        ```mermaid
        flowchart TD
          A[Problem grows] --> B[Many if/else and duplicated logic]
          B --> C[Hard to maintain]
          A --> D[Use pattern where it fits]
          D --> E[Cleaner structure]
          E --> F[Easier extension]
        ```
        
        ## Remember
        
        - Patterns are reusable solutions
        - Use when it improves readability and scaling
        - Don’t force patterns into small/simple code
        
#Python#Advanced#Design Patterns