Design Patterns
Master the essential design patterns used in professional Python development. Learn Singleton, Factory, and Strategy patterns with real-world examples and best practices.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1. What Are Design Patterns (Really)?
Design patterns are reusable solutions to common design problems in software.
They're not code you copy 1:1. They're mental templates you adapt:
Part 1: Singleton Pattern
2. Singleton Pattern — Intent & When to Use
Intent: Ensure only one instance of a class exists, and provide a global access point to it.
3. The Simplest Python Singleton: Just Use a Module
Instead of creating a complex class-based singleton, you can just create a module:
👉 For many apps, this is the most Pythonic "singleton".
Only use heavy OO-singleton patterns if you really need class-based behaviour.
4. Classic OO Singleton With __new__
5. Singleton via Decorator (Reusable & Clean)
We can build a @singleton decorator that turns any class into a singleton:
6. The Borg Pattern (Shared State Singleton)
Changing an attribute in one changes it for all.
7. Singleton in Real Projects — When & When NOT to Use
Example of something better than a singleton: dependency injection:
Part 2: Factory Patterns
Factory patterns control how objects are created :
8. Simple Factory (Function-Based)
This is the most Pythonic and often best starting point.
We want to create different notification senders: email, SMS, push.
If you add WhatsApp later, only one place changes.
9. Improving the Simple Factory with a Registry
Instead of if/elif, we can use a mapping (much cleaner for many types).
This "simple factory + registry" pattern is used everywhere in real-world Python code (ML frameworks, plugin systems, etc.).
10. Factory Method Pattern (OO Style)
Sometimes you don't want a separate function, you want subclasses to decide what they create.
Factory Method = a method in a parent class that is overridden in subclasses to decide what object to create.
11. Abstract Factory — Creating "Families" of Related Objects
You're building a cross-platform GUI toolkit:
Abstract Factory returns a family of related objects.
Part 3: Strategy Pattern
The Strategy pattern allows you to change how something works without changing the code that uses it.
Python makes this pattern extremely powerful because functions are first-class objects.
12. Why Strategy Pattern Exists
13. Strategy Pattern — Functional (Most Pythonic)
The simplest and BEST way in Python is using functions as strategies.
14. Strategy Using Classes (Classic OOP Approach)
Sometimes you need stateful strategies or polymorphism.
15. Strategy in Real Systems
▶ 1. Machine Learning Preprocessing Pipelines
Choose pricing or fraud-checking algorithms at runtime.
🎓 Conclusion
You now fully understand all 3 major design patterns:
Control instance creation, global state, config, caching.
📋 Quick Reference — Design Patterns
You can now recognise and apply the most important design patterns — the vocabulary every senior engineer uses when discussing architecture.
Up next: Module Architecture — structure large Python codebases with clear boundaries and imports.
Practice quiz
Which problem does the Singleton pattern solve?
- Swapping algorithms at runtime
- Creating families of related objects
- Ensuring only one instance exists with a global access point
- Adding behavior to a class dynamically
Answer: Ensuring only one instance exists with a global access point. Singleton guarantees a single instance (e.g. a config or DB pool) and provides one global access point to it.
What is the most Pythonic 'singleton' for many simple cases?
- Just a module — imported once and cached in sys.modules
- A metaclass
- A global list
- A frozen dataclass
Answer: Just a module — imported once and cached in sys.modules. A module is imported once and cached in sys.modules, so every import gets the same object — a natural singleton.
In the classic singleton, which method is overridden to control instance creation?
- __init__
- __call__
- __enter__
- __new__
Answer: __new__. __new__ controls object creation, so it returns the stored single instance; __init__ only initializes.
What distinguishes the Borg pattern from a classic singleton?
- It forbids inheritance
- Many instances exist but they share the same state via __dict__
- It allows only one instance
- It caches return values
Answer: Many instances exist but they share the same state via __dict__. Borg instances are distinct objects (s1 is s2 is False) yet share one __dict__, so they share all state.
What does a simple (function-based) factory like create_notifier('email') achieve?
- It centralizes the 'which class?' decision so callers don't use if/elif everywhere
- It caches notifications
- It makes the class a singleton
- It validates argument types
Answer: It centralizes the 'which class?' decision so callers don't use if/elif everywhere. The factory hides class-selection logic in one place, so app code just asks for 'email' without knowing the concrete class.
How does a registry improve a simple factory?
- It adds threading
- It removes the need for classes
- It replaces if/elif chains with a dictionary mapping names to classes
- It enforces a single instance
Answer: It replaces if/elif chains with a dictionary mapping names to classes. A registry dict maps keys to classes, so adding a new type is just one dictionary entry instead of another elif branch.
In the Factory Method pattern, who decides which concrete object is created?
- A standalone function
- Subclasses, by overriding the factory method
- The caller passes the class in
- A global registry only
Answer: Subclasses, by overriding the factory method. Factory Method puts a create_*() method in the base class that each subclass overrides to return its own product.
What does an Abstract Factory return?
- A single object
- A cached value
- A function
- A family of related objects (e.g. matching Button and Checkbox)
Answer: A family of related objects (e.g. matching Button and Checkbox). Abstract Factory produces whole families of related objects, ensuring you never mix incompatible components.
What is the most Pythonic way to implement the Strategy pattern?
- A deep class hierarchy
- Functions as first-class strategies stored in a dict
- A singleton per strategy
- Global if/elif branches
Answer: Functions as first-class strategies stored in a dict. Because functions are first-class in Python, storing them in a strategy dict is the simplest, fastest approach.
Which principle does replacing if/elif algorithm-selection with Strategy uphold?
- DRY only
- Single instance guarantee
- The Open-Closed Principle (open for extension, closed for modification)
- Lazy initialization
Answer: The Open-Closed Principle (open for extension, closed for modification). Strategy lets you add new behaviors without editing existing selection code, honoring the Open-Closed Principle.