DEV Community

Cover image for Strategy: The Google Maps Travel-Mode Pattern
Vignesh Athiappan
Vignesh Athiappan

Posted on

Strategy: The Google Maps Travel-Mode Pattern

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...
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)