Before you start
Strategy is the most common behavioral pattern in real code. Nearly every "algorithm-shaped" decision — pricing, routing, scheduling, sorting, compressing, retrying — uses it, whether or not it's called "Strategy" out loud.
The one-line version
Strategy puts each algorithm into its own class so callers can swap between them without changing any code around them.
The signal to use Strategy
- You have if/elif on a "type of operation" — the classic smell (pricing type, retry type, notification channel).
- The choice is made at runtime, not fixed at code time.
- The algorithms are independent — no shared state tying them together.
- You need to test each one on its own.
Any two of these → probably Strategy.
How this connects to OCP + composition
Strategy is a specific use of:
- Open/Closed Principle — add new behavior by writing a new strategy class, not by editing existing dispatch code.
- Composition over inheritance — a
CartHAS a strategy (composition), rather than BEING a specific strategy (inheritance).
If you got OCP + composition from earlier modules, Strategy is the named packaging of that habit.
Where Strategy shows up in real code
- Django Paginator — pass a custom pagination strategy
- Sort keys —
sorted(items, key=lambda x: x.date)is Strategy-in-lambda-form - Kubernetes scheduler plugins
- Retry policies in libraries like
tenacity - Cache eviction — LRU, LFU, FIFO all pluggable
- Load balancers — RoundRobin, LeastConnections
- Payment methods — you built this in module 1 lesson 5. That was Strategy.
- Discount calculators — module 2 lesson 2. Strategy.
Strategy vs its cousins
| Pattern | What it varies |
|---|---|
| Strategy | The ALGORITHM used for one operation |
| State (next lesson) | The BEHAVIOR based on the object's internal state |
| Command | The ACTION as a first-class object |
| Observer | WHO REACTS when something changes |
Strategy is specifically about algorithm choice. If you're NOT choosing between algorithms, use a different pattern.
The interview shape
Any question of the form "you have N different ways to do X — design it" is Strategy. Watch for:
- "Different pricing tiers"
- "Different shipping methods"
- "Different sorting algorithms"
- "Different rate-limiting approaches"
- "Different matchmaking algorithms"
Every one has the same Strategy shape. Learn the shape once — apply it everywhere.
The "just pass a function" alternative
In Python you can often replace Strategy with a
callable:
cart.set_shipping(lambda w, d: 5 * d)
Cleaner for one-off cases. But you lose:
- Type checking / interface rules
- A named identity (a function has no clear name for logging)
- Per-strategy state (a strategy with rate tables loaded from config)
For interviews, prefer the class-based Strategy — it shows design maturity and is easier to explain. Use lambdas only when the strategy really is just a simple function.
The decision cheat-sheet
| Situation | Pick |
|---|---|
| N algorithms for one operation, choice at runtime | Strategy |
| N algorithms fixed at code time | Inheritance is fine |
| Algorithm needs per-instance config | Strategy classes with __init__ |
| Simple algorithm, one-off | Pass a lambda |
| Object's behavior CHANGES over its lifetime | State (next lesson) |
| Actions need to be queued / undone / logged | Command (lesson 13) |