๐Ÿงฉ Full Lesson ยท Programming Concepts
Singleton, Factory, Observer, Strategy โ€” Named Solutions to Recurring Problems
Common Design Patterns

Programmers kept independently reinventing the same handful of solutions to the same recurring design problems โ€” design patterns are simply those solutions, named and documented, so teams can communicate about them with a single shared word instead of re-explaining the whole idea every time.

The Core Idea
Named, Reusable Solutions to Recurring Design Problems

A design pattern is a general, reusable solution to a commonly-occurring problem in software design โ€” not a specific piece of code you copy and paste, but a proven STRUCTURE or approach you adapt to your specific situation. Patterns emerged because experienced developers kept noticing the same underlying design problems appearing across completely different projects and domains, and kept independently arriving at similar structural solutions.

The real value of design patterns is largely in shared VOCABULARY: saying 'let's use an Observer pattern here' instantly communicates an entire well-understood structural approach to another developer familiar with the pattern, rather than requiring a lengthy from-scratch explanation of the intended design every single time.

๐Ÿ’ก Memory Trick
SINGLETON is a country having exactly one official currency mint โ€” no matter how many times you ask 'where do official coins come from,' there's only ever one authoritative source. FACTORY is a restaurant kitchen that takes your general order ('a pasta dish') and decides internally which specific pasta to actually prepare, without you needing to specify the exact recipe yourself. OBSERVER is a magazine subscription โ€” subscribers automatically get notified with the newest issue the moment it's published, without the publisher needing to know each individual subscriber's specific business. STRATEGY is choosing between different route options on a GPS (fastest, shortest, avoid tolls) โ€” the underlying navigation goal is identical, but you can swap in a completely different calculation approach without changing anything else about how you use the GPS.
Four Foundational Patterns
What Each One Specifically Solves
1
Singleton
Ensures a class has exactly one instance throughout the entire application, and provides a single global point of access to that one instance. Useful for things like a single shared configuration object or a single connection pool manager โ€” situations where having multiple independent instances would create inconsistency or wasted resources.
2
Factory
Provides an interface for creating objects, letting the calling code request 'an object of this general type' without needing to know or specify the exact concrete class being instantiated. This is especially useful when the exact type of object needed depends on some runtime condition, and you want to keep that decision logic centralized in one place rather than scattered throughout the calling code.
3
Observer
Defines a one-to-many relationship where multiple 'observer' objects are automatically notified whenever a single 'subject' object's state changes, without the subject needing any specific knowledge of who its observers are or what they'll do with the notification. This is the foundational pattern behind most event-handling systems and reactive user interfaces.
4
Strategy
Defines a family of interchangeable algorithms (or behaviors) behind a common interface, letting the specific algorithm used be selected and swapped at runtime without changing the code that USES that algorithm. This is directly related to polymorphism (from the 4 Pillars of OOP lesson) โ€” different strategy objects implement the same shared interface differently.
Using Patterns Appropriately
A Named Solution, Not a Mandatory Checklist

Design patterns should be applied when they genuinely fit a real recurring problem you're actually facing โ€” not forced into a design just because you recognize the pattern's name and want to demonstrate familiarity with it. Applying a Singleton where multiple instances would actually be perfectly fine (or even preferable, for testing purposes) just adds unnecessary rigidity; applying a complex pattern to solve a genuinely simple problem that didn't need that structure is a common sign of over-engineering.

This connects directly to the SOLID principles from the previous lesson โ€” many design patterns are, in effect, concrete, named techniques for actually achieving SOLID's more abstract goals in practice; the Strategy pattern, for instance, is a direct, practical way of satisfying the Open/Closed Principle for swappable algorithm behavior.

๐Ÿ–ฅ๏ธ Applied Scenario
You're building a shipping cost calculator that needs to support several different calculation methods (flat rate, weight-based, distance-based), with the ability to add new calculation methods later without modifying existing, already-tested code.
1
You recognize this as a textbook Strategy pattern situation: the underlying goal ('calculate shipping cost') stays the same, but the specific calculation approach needs to vary and be swappable.
2
You define a shared ShippingStrategy interface with a single calculateCost() method, then implement FlatRateStrategy, WeightBasedStrategy, and DistanceBasedStrategy as separate classes, each implementing that same interface differently.
3
Your checkout code simply calls strategy.calculateCost() on whichever strategy object was selected, with no if/else branches checking which specific calculation method is in use.
4
Conclusion: adding a brand-new calculation method later (say, a promotional 'free shipping over $50' strategy) requires only adding a NEW class implementing the same shared interface, with zero modification needed to the existing checkout code or any of the other already-working strategy implementations โ€” directly satisfying the Open/Closed Principle through the Strategy pattern.
๐Ÿ“Œ Exam Application
Exam questions frequently describe a design problem and ask you to identify which design pattern best solves it, expecting you to justify the choice based on the specific structural need (single shared instance, flexible object creation, automatic multi-object notification, or swappable algorithms). You may also be asked to explain the relationship between a specific design pattern and the SOLID principle(s) it helps satisfy.
โš ๏ธ Most Common Common Design Patterns Mistakes
The most common mistake is applying a design pattern because it's recognized or familiar, rather than because it genuinely fits the actual problem at hand โ€” forcing a Singleton onto a class that would work fine (or better) with multiple instances, or wrapping a Strategy pattern around a genuinely fixed, never-changing single algorithm, adds unnecessary complexity without a corresponding real benefit. Another frequent error is confusing Factory (creating OBJECTS based on some condition) with Strategy (selecting BEHAVIOR/algorithms to use) โ€” both involve some form of 'choosing what to use based on a condition,' but Factory is about object creation while Strategy is about swapping interchangeable behavior in code that's already been given its object.
โœ“ Quick Self-Test
Can you match each of Singleton, Factory, Observer, and Strategy to a concrete real-world scenario where it would be the appropriate pattern to use? Given a described design problem, can you identify which pattern best fits it and justify your reasoning based on the specific structural need?
Next Lesson
Version Control with Git
โ†’
โ† All Programming Concepts Lessons