Step 1 Understand it
The problem it solves. When an algorithm can vary (pricing, sorting, routing), putting every variant in one method with if/else makes it long, hard to test and risky to extend.
New words in this topic (tap one to see what it means)
Watch it happen
Read the animation as text
- Instead of an if/elif on the pricing type inside Ride, each pricing rule is its own class with the same method: price(distance_km).
- Ride holds one strategy and just calls it. Normal pricing for 10 km: £14.50.
- Rush hour: swap the strategy at runtime — from configuration, a factory or the clock. Same Ride, same call: £26.10.
- A new rule is a new class. Ride never changes, and each strategy can be tested on its own.
Picture it
classDiagram
class Ride {
-pricing
+fare(km)
}
class PricingStrategy {
<<interface>>
+price(km)
}
Ride o-- PricingStrategy
PricingStrategy <|.. NormalPricing
PricingStrategy <|.. SurgePricing
PricingStrategy <|.. NightPricingThe idea
Instead of an if/elif on pricing type inside checkout, each pricing rule is its own (or function) with the same method. Checkout holds one strategy and can swap it.
How it works, step by step
- Define the interface: price(distance_km).
- Write one class per algorithm: NormalPricing, SurgePricing, NightPricing.
- The context (Ride) holds one strategy object and calls it.
- Choose the strategy at runtime: from configuration, a , or the time of day.
Analogy
Choosing a route in a maps app: fastest, shortest or avoiding tolls. Same journey, different strategy.
Where the analogy breaks
The maps app chooses for you when you tap a button. In code, something still has to decide which strategy to use, often a factory or configuration.
Example
Payment fees, sorting, compression formats, and ride pricing (normal or ).
Must-know points
- Replaces 'which algorithm?' conditionals with .
- Strategies can be swapped at runtime.
- In Python, plain functions can be strategies.
- Very common in LLD answers: pricing, payment, parking fees.
Common mistakes
- Strategies that need lots of the context's private data (a sign the interface is wrong).
- Creating strategy classes for one fixed algorithm.
class NormalPricing:
def price(self, distance_km): return 2 + 1.2 * distance_km
class SurgePricing:
def __init__(self, multiplier): self.multiplier = multiplier
def price(self, distance_km): return (2 + 1.2 * distance_km) * self.multiplier
class Ride:
def __init__(self, pricing): self.pricing = pricing # a swappable strategy
def fare(self, km): return round(self.pricing.price(km), 2)
Ride(NormalPricing()).fare(10) # 14.0
Ride(SurgePricing(1.5)).fare(10) # 21.0Step 2 Go further (free, optional)
Optional. The notes above are written to be enough on their own. These free resources give a second explanation and extra practice.
-
Watch
Christopher Okhravi · free on YouTube
-
Read
Refactoring.Guru, free
Step 3 Practise
Try each exercise yourself first: on paper, out loud or in code. Then open the answer and compare it with yours.
-
ExplainSay it in plain words in under a minute, with no notes.
Explain Strategy with the route-choice picture.
Show answer
In a maps app, the journey is the same, from home to the airport, but you choose how the route is worked out: fastest, shortest, or avoiding tolls. The app doesn't care which you pick; it asks the chosen option for a route and follows it. You can switch options without changing anything else.
Strategy is that idea in code. One job (working out a ride's price) has several interchangeable ways of being done (normal pricing, surge pricing). Each way is its own class (or function) with the same method, price(distance). The Ride holds one strategy and calls it, without knowing which one it has. Swapping the strategy changes the behaviour; adding a new one needs no change to Ride. It replaces an if/elif on "pricing type" in the middle of the business code.
-
DrawSketch the diagram (or class diagram) from memory.
Draw Ride with a PricingStrategy interface and two implementations.
Show answer
Ride holds one PricingStrategy and only ever calls price(). Each implementation is interchangeable. Night pricing is added as one more box at the bottom, without touching Ride.
textRide - pricing: PricingStrategy ◆──► «interface» PricingStrategy + fare(km) + price(distance_km) △ △ △ ┊ ┊ ┊ NormalPricing SurgePricing NightPricing 2 + 1.2 × km normal × 1.5 normal + £3 (added later) -
ApplyUse it in a real design question and say exactly where it fits.
Add a 'night pricing' strategy without changing Ride, and write tests for all three.
Show answer
NightPricing is one new class with the same price() method: here a flat £3 on top of the normal fare. Ride is not changed. Each strategy gets a test for a 10 km ride: normal £14.00, surge (× 1.5) £21.00, night £17.00, and one more test checks that strategies can be swapped on the same ride.
pythonclass NormalPricing: def price(self, distance_km): return 2 + 1.2 * distance_km class SurgePricing: def __init__(self, multiplier): self.multiplier = multiplier def price(self, distance_km): return (2 + 1.2 * distance_km) * self.multiplier class NightPricing: # new: Ride is not changed def price(self, distance_km): return NormalPricing().price(distance_km) + 3 class Ride: def __init__(self, pricing): self.pricing = pricing def fare(self, km): return round(self.pricing.price(km), 2) def test_normal(): assert Ride(NormalPricing()).fare(10) == 14.0 def test_surge(): assert Ride(SurgePricing(1.5)).fare(10) == 21.0 def test_night(): assert Ride(NightPricing()).fare(10) == 17.0 def test_strategy_can_be_swapped(): ride = Ride(NormalPricing()) ride.pricing = NightPricing() assert ride.fare(10) == 17.0 for test in (test_normal, test_surge, test_night, test_strategy_can_be_swapped): test() print("all 4 tests passed") # all 4 tests passed -
Trade-offsSay what it costs, when not to use it, and the alternative.
When is a simple if/else better than Strategy?
Show answer
• Two or three options that rarely change, each only a line or two: an if/else is shorter and easier to read than an interface and three classes.
• The choice is used in one place only, so nothing else would reuse the strategies.
• The behaviour never needs to be swapped at runtime, configured, or tested separately.
• It is really data, not behaviour: if the options only differ in numbers (a rate per km), a table of numbers is enough.In Python there is also a lighter middle ground: functions are already strategies. Pass a function, or keep a dictionary from name to function, without writing classes.
Move to Strategy when the options multiply, when each grows its own logic, when other teams add options, or when you want to test each option on its own.
Step 4 Interview-ready, then prove it
Your interview answer
About 20 to 40 seconds, said out loud. Practise it until it sounds like you, not like notes.
Strategy puts each interchangeable algorithm, like normal or surge pricing, behind one interface, so the class using it can switch algorithms at runtime, and new ones are added without editing it.
Follow-up questions
Strategy or State?
Both swap behaviour objects. With Strategy, the caller chooses the algorithm. With State, the object changes its own state as happen.
Tick each check when you can do it without notes
A topic is finished when you pass all four checks, not when you finish a video. Be strict: if you needed your notes, it is not ticked yet.
- Explain Say it in plain words in under a minute, with no notes.
- Draw Sketch the diagram (or class diagram) from memory.
- Apply Use it in a real design question and say exactly where it fits.
- Trade-offs Say what it costs, when not to use it, and the alternative.
0 of 4 checks ticked.
Saved in this browser. Back it up or move it to another device.