.NET  

Strategy Pattern in .NET 10

Introduction

We frequently encounter scenarios in real-world applications where we can apply multiple algorithms or behaviors, depending on the conditions.

For example:

  • Different discount calculations

  • Multiple payment methods

  • Various file processing strategies

Instead of writing messy prose if-else or switch statements, we can use the Strategy Design Pattern.

What is the strategy pattern?

The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one, and make them interchangeable at runtime.

In simple words: Select behavior dynamically without changing the main code.

Problem Without Strategy Pattern

public class DiscountService
{
    public double GetDiscount(string customerType, double amount)
    {
        if (customerType == "Regular")
            return amount * 0.1;
        else if (customerType == "Premium")
            return amount * 0.2;
        else if (customerType == "VIP")
            return amount * 0.3;

        return 0;
    }
}

Issues

  • Violates Open/Closed Principle

  • Hard to maintain

  • Adding new logic requires modifying existing code

Solution Using Strategy Pattern

  • Define Strategy Interface

public interface IDiscountStrategy
{
    string Key { get; }   // Unique identifier
    double CalculateDiscount(double amount);
}
  • Create Concrete Strategies


public class RegularDiscount : IDiscountStrategy
{
    public string Key => "Regular";

    public double CalculateDiscount(double amount)
        => amount * 0.1;
}

public class PremiumDiscount : IDiscountStrategy
{
    public string Key => "Premium";

    public double CalculateDiscount(double amount)
        => amount * 0.2;
}

public class VipDiscount : IDiscountStrategy
{
    public string Key => "VIP";

    public double CalculateDiscount(double amount)
        => amount * 0.3;
}
  • Use Strategy via Dependency Injection (program.cs)


builder.Services.AddScoped<IDiscountStrategy, RegularDiscount>();
builder.Services.AddScoped<IDiscountStrategy, PremiumDiscount>();
builder.Services.AddScoped<IDiscountStrategy, VipDiscount>();

builder.Services.AddScoped<DiscountFactory>();
  • Strategy Resolver (Factory + Dictionary)

public class DiscountFactory
{
    private readonly Dictionary<string, IDiscountStrategy> _strategies;

    public DiscountFactory(IEnumerable<IDiscountStrategy> strategies)
    {
        _strategies = strategies.ToDictionary(s => s.Key, StringComparer.OrdinalIgnoreCase);
    }

    public IDiscountStrategy GetStrategy(string type)
    {
        if (_strategies.TryGetValue(type, out var strategy))
            return strategy;

        throw new KeyNotFoundException($"No strategy found for type: {type}");
    }
}
  • Use in Controller


[ApiController]
[Route("api/[controller]")]
public class DiscountController : ControllerBase
{
    private readonly DiscountFactory _factory;

    public DiscountController(DiscountFactory factory)
    {
        _factory = factory;
    }

    [HttpGet]
    public IActionResult GetDiscount(string type, double amount)
    {
        var strategy = _factory.GetStrategy(type);
        var result = strategy.CalculateDiscount(amount);

        return Ok(result);
    }
}

Benefits of Strategy Pattern

  • Follows Open/Closed Principle

  • Removes complex if-else

  • Easy to add new strategies

  • Improves testability

  • Clean and maintainable code

When NOT to Use

  • If you only have 2 simple conditions

  • If logic is unlikely to change

  • Over-engineering small features

Real-World Use Cases

  • Payment gateways (UPI, Card, NetBanking)

  • Logging strategies

  • Sorting algorithms

  • Notification systems (Email, SMS, Push)

Conclusion

The Strategy Pattern is a powerful way to write clean, scalable, and maintainable code in ASP.NET Core.

Instead of changing existing logic, you simply add new strategies — making your system flexible and future-proof.