Strategy: The Google Maps Travel-Mode Pattern
You open Google Maps to go somewhere, and it asks: how do you want to travel? By car, walking, public transport, or cycling.
Same goal — get from A to B — but each option runs a completely different algorithm to work out the route. You pick one, and Maps swaps in that method. Tomorrow you pick another; same app, different strategy, chosen at runtime.
That's the Strategy pattern: a family of interchangeable algorithms, picked and swapped at runtime.
The problem it solves
Say you calculate shipping cost, and it depends on the method:
public decimal CalculateShipping(string method, decimal weight)
{
if (method == "standard") return weight * 5;
else if (method == "express") return weight * 10 + 20;
else if (method == "overnight") return weight * 15 + 50;
// add "drone"? edit this method again...
}
Every new method means editing this one function. It becomes a dumping ground of ifs — hard to test each branch alone, and it keeps forcing you to modify code that already works.
The Strategy way
Define the shape all algorithms share:
public interface IShippingStrategy
{
decimal Calculate(decimal weight);
}
Each algorithm becomes its own small class:
public class StandardShipping : IShippingStrategy
{
public decimal Calculate(decimal weight) => weight * 5;
}
public class ExpressShipping : IShippingStrategy
{
public decimal Calculate(decimal weight) => weight * 10 + 20;
}
public class OvernightShipping : IShippingStrategy
{
public decimal Calculate(decimal weight) => weight * 15 + 50;
}
The context holds a strategy and delegates to it, without knowing which one:
public class ShippingCalculator
{
private IShippingStrategy _strategy;
public ShippingCalculator(IShippingStrategy strategy) => _strategy = strategy;
public void SetStrategy(IShippingStrategy strategy) => _strategy = strategy;
public decimal Calculate(decimal weight) => _strategy.Calculate(weight);
}
Swap strategies at runtime:
var calc = new ShippingCalculator(new StandardShipping());
Console.WriteLine(calc.Calculate(10)); // 50
calc.SetStrategy(new ExpressShipping()); // swapped the algorithm, same object
Console.WriteLine(calc.Calculate(10)); // 120
Add drone delivery? Write one DroneShipping class. The calculator never changes. You add a new class instead of modifying working code.
The idea behind it
Strategy replaces a big conditional — an if/else or switch picking behavior — with a set of small classes plus composition. Instead of the code deciding what to do inside one method, you hand it the behavior you want.
Don't bury the "how" inside an if-else. Inject the way to do it.
The C# shortcut
For simple strategies you don't even need classes — just pass a function:
public class ShippingCalculator
{
private Func<decimal, decimal> _strategy;
public ShippingCalculator(Func<decimal, decimal> strategy) => _strategy = strategy;
public decimal Calculate(decimal weight) => _strategy(weight);
}
var standard = new ShippingCalculator(w => w * 5);
var express = new ShippingCalculator(w => w * 10 + 20);
A Func<> or lambda is a strategy. Every time you pass a comparison to list.Sort(...) or a predicate to .Where(...), you're using Strategy. LINQ is soaked in it.
Strategy vs Factory
These get confused, but the jobs are different:
- Factory decides which object to create — its job is creation.
- Strategy decides which algorithm to run — its job is behavior.
They often team up: a factory creates the right strategy, then the context runs it.
Where you've seen it
-
LINQ —
.Where(predicate),.OrderBy(selector); predicates and selectors are strategies. -
List.Sort(IComparer)— the comparer is a pluggable sorting strategy. - Payment processing — pick Card, UPI, or Wallet strategy at checkout.
- Compression, encryption, pricing rules, discount engines — anywhere "same task, multiple methods."
One line to remember
Strategy = Google Maps travel mode. Same goal, a family of swappable algorithms, pick one at runtime — adding a new one never touches existing code.
Part 10 of a series on must-know design patterns in C#, explained the simple way. Earlier parts covered Singleton, Factory Method, Builder, Adapter, Decorator, Facade, Proxy, Composite, and Observer. Next up: Command — wrapping a request as an object.
Top comments (0)