System DesignEasy
What is the Strategy pattern and when should you use it?
Strategy encapsulates a family of interchangeable algorithms. The consumer holds the algorithm via an interface; you swap implementations at runtime or compile time.
public interface IPricingStrategy {
decimal Apply(Order order);
}
public sealed class FlatRatePricing(decimal flat) : IPricingStrategy {
public decimal Apply(Order o) => flat;
}
public sealed class TieredPricing : IPricingStrategy {
public decimal Apply(Order o) => o.Total switch {
> 1000m => o.Total * 0.9m,
> 500m => o.Total * 0.95m,
_ => o.Total
};
}
public sealed class Checkout(IPricingStrategy pricing) {
public decimal Calculate(Order o) => pricing.Apply(o);
}
Use it when:
- The same operation has several legitimate variants (tax rules per region, retry policies, sort orders)
- You're tempted to write
if (regionType == "EU") ... else if ("US") ...— that's a Strategy in disguise - You need to change behaviour at runtime (admin toggles a feature flag → swaps strategy via DI)
- Different environments need different behaviour (dev uses InMemoryCacheStrategy, prod uses RedisCacheStrategy)
Don't use it for:
- A single algorithm that "might change someday" — wait until that day
- Variations that share less than 70% of context (you're really looking at different methods, not strategies)
Modern C# alternative for closed sets: a switch expression on a discriminated record union is often clearer than a Strategy hierarchy with two implementations.