Introduction

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

For example:

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

Solution Using Strategy Pattern

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

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;
}

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

builder.Services.AddScoped<DiscountFactory>();
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}");
    }
}

[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

When NOT to Use

Real-World Use Cases

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.