Choosing the Right Pattern
Choosing the right design pattern starts with correctly diagnosing the problem, not with picking a favorite pattern and looking for a place to use it. The most reliable approach is to name the specific symptom in the existing code first — repeated conditional branches on type, an object with too many constructor parameters, tightly coupled classes that are hard to test in isolation — and then match that symptom to the smallest pattern that resolves it. Jumping straight to an architecture diagram full of patterns before writing the simplest working version almost always produces an over-engineered result that's harder to change than plain code would have been.
Cricket analogy: A captain diagnosing that the opposition is weak against short-pitched bowling before setting the field, rather than copying a generic aggressive field from another match, mirrors matching a pattern to the actual diagnosed symptom in code.
A Practical Decision Framework
A workable heuristic: if you're duplicating creation logic across the codebase, look at Factory Method or Abstract Factory; if a class is accumulating conditional branches based on an object's type or state, consider Strategy or State; if unrelated objects need to react to one object's changes, consider Observer; if you need to add optional behavior without an explosion of subclasses, consider Decorator; if two incompatible interfaces need to cooperate, consider Adapter. Crucially, this matching should happen after you've felt the pain of the problem in real code — writing the simplest solution first and refactoring toward a pattern once a second or third variation appears is safer than guessing upfront which pattern a not-yet-written feature will need.
Cricket analogy: A team only invests in specialist death-overs bowling coaching once they've actually lost multiple matches in the final overs, not before facing that specific recurring problem, mirroring refactoring toward a pattern only after the pain is felt.
# Refactor toward a pattern once real duplication appears, not before.
# Version 1: two payment types, simple if/else is fine
def process_payment(kind, amount):
if kind == "credit_card":
return f"Charged ${amount} to card"
elif kind == "paypal":
return f"Sent ${amount} via PayPal"
# Version 2: a third and fourth type appear, conditionals keep growing ->
# NOW refactor toward Strategy, because the pain (duplication, growing
# branching) is real, not hypothetical.
class PaymentStrategy:
def pay(self, amount): raise NotImplementedError
class CreditCardStrategy(PaymentStrategy):
def pay(self, amount): return f"Charged ${amount} to card"
class PayPalStrategy(PaymentStrategy):
def pay(self, amount): return f"Sent ${amount} via PayPal"
class CryptoStrategy(PaymentStrategy):
def pay(self, amount): return f"Transferred ${amount} in crypto"
class GiftCardStrategy(PaymentStrategy):
def pay(self, amount): return f"Redeemed ${amount} from gift card"
Common Mistakes When Selecting a Pattern
The most common mistake is 'pattern hammer' syndrome — having just learned Observer, a developer starts seeing pub/sub opportunities everywhere, including places where a simple direct method call would be clearer. The second common mistake is combining too many patterns in one place, producing a maze of Factories creating Strategies wrapped in Decorators that no one on the team can trace during an incident at 2 a.m. The fix for both is the same discipline: prefer the simplest structure that solves the diagnosed problem, add a pattern only when a specific, named pain point justifies the added indirection, and be willing to remove a pattern later if the assumptions that justified it change.
Cricket analogy: A bowler who just learned a devastating slower ball starts bowling it every single delivery regardless of the batter or situation, the way a developer who just learned Observer starts applying pub/sub everywhere regardless of fit.
A good litmus test before adding a pattern: can you point to a specific line of code, or a specific bug report, that the pattern would have prevented or simplified? If not, you may be solving an imagined problem instead of a real one.
Combining multiple patterns in a single feature — a Factory that creates Strategies wrapped in Decorators managed by a Mediator — can quickly become unreadable. Each additional pattern layer should pay for itself in reduced complexity elsewhere; if it doesn't, simplify.
- Diagnose the specific symptom in the code first; don't start from a favorite pattern.
- Repeated type-based conditionals often point to Strategy or Factory Method.
- Cross-object reactions to one object's changes often point to Observer.
- Optional behavior without subclass explosion often points to Decorator.
- Incompatible interfaces needing to cooperate often point to Adapter.
- Refactor toward a pattern once real duplication or pain appears — don't guess upfront.
- Avoid 'pattern hammer' syndrome and stacking too many patterns in one place.
Practice what you learned
1. What should come first when choosing a design pattern?
2. Repeated conditional branches based on an object's type most often suggest which pattern(s)?
3. What is 'pattern hammer' syndrome?
4. According to the recommended approach, when should you refactor toward a pattern?
5. What is a good litmus test before adding a pattern to a codebase?
Was this page helpful?
You May Also Like
What Are Design Patterns?
An introduction to what design patterns actually are, how they differ from algorithms and libraries, and when applying one genuinely helps versus adds needless complexity.
SOLID Principles Recap
A refresher on the five SOLID object-oriented design principles and how they form the underlying rationale for many Gang of Four design patterns.
The Gang of Four and Pattern Categories
How the 1994 Gang of Four catalog organized 23 object-oriented design patterns into Creational, Structural, and Behavioral categories, with representative examples of each.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringSoftware Engineering Study Notes
Python · 40 topics
Software EngineeringGit & Version Control Study Notes
Bash · 40 topics
Software EngineeringSystem Design Study Notes
Architecture · 40 topics