💻 Programming intermediate

Design Pattern

A reusable solution template for commonly occurring problems in software design, providing proven approaches to structure code.

What is a Design Pattern?

A design pattern is a general, reusable solution to a commonly occurring problem in software design. It's not finished code, but rather a template or blueprint that can be applied to solve a particular design challenge in many different situations.

Origin

Design patterns were popularized by the "Gang of Four" (GoF) book Design Patterns: Elements of Reusable Object-Oriented Software (1994) by Gamma, Helm, Johnson, and Vlissides.

Pattern Categories

1. Creational Patterns

Control object creation mechanisms.

Pattern Purpose
Singleton Ensure only one instance exists
Factory Create objects without specifying exact class
Builder Construct complex objects step by step
Prototype Clone existing objects

2. Structural Patterns

Compose objects into larger structures.

Pattern Purpose
Adapter Make incompatible interfaces work together
Decorator Add behavior to objects dynamically
Facade Provide simplified interface to complex subsystem
Proxy Control access to an object

3. Behavioral Patterns

Define communication between objects.

Pattern Purpose
Observer Notify dependents of state changes
Strategy Define family of interchangeable algorithms
Command Encapsulate requests as objects
Iterator Access elements sequentially

Examples

Singleton Pattern (Python)

class DatabaseConnection:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.connection = cls._connect()
        return cls._instance

    @staticmethod
    def _connect():
        return "Connected to database"

# Both variables reference the same instance
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # True

Observer Pattern (TypeScript)

interface Observer {
    update(data: any): void;
}

class Subject {
    private observers: Observer[] = [];

    subscribe(observer: Observer) {
        this.observers.push(observer);
    }

    notify(data: any) {
        this.observers.forEach(obs => obs.update(data));
    }
}

Factory Pattern (Python)

class AnimalFactory:
    @staticmethod
    def create(animal_type: str):
        if animal_type == "dog":
            return Dog()
        elif animal_type == "cat":
            return Cat()
        raise ValueError(f"Unknown animal: {animal_type}")

pet = AnimalFactory.create("dog")

Modern Alternatives

Some classic patterns are less relevant in modern languages:

  • Iterator → Built into most languages (for...of, generators)
  • Strategy → First-class functions / lambdas
  • Singleton → Dependency injection containers

When to Use Patterns

Do use when:

  • You recognize a recurring problem
  • The pattern fits naturally
  • It improves code clarity

Avoid when:

  • Simpler solutions exist
  • Over-engineering for future flexibility
  • Pattern doesn't fit the problem

// Example Usage

The Observer pattern is the foundation of reactive programming libraries like RxJS and event-driven architectures.