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
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.