DEV Community

Cover image for Understanding the Strategy Pattern in C# with a VAT Calculation Example
Daniel Azevedo
Daniel Azevedo

Posted on

Understanding the Strategy Pattern in C# with a VAT Calculation Example

Hi devs,

The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one, and make them interchangeable. It helps in situations where multiple strategies (algorithms) can be used depending on the context, making the code more flexible and easier to maintain.

In this article, we’ll explain the Strategy Pattern by calculating VAT (Value Added Tax) for three different countries: Portugal (PT), France (FR), and Spain (SP). The idea is to show how you can easily switch between the different VAT calculation strategies without altering the core application logic.

Why Use the Strategy Pattern?

In real-world applications, there are often multiple ways to perform a certain task. For example, VAT rates differ across countries. Without the Strategy Pattern, you might end up using complex if-else or switch-case statements to determine the correct VAT calculation, which can make your code harder to read and maintain. The Strategy Pattern allows you to offload this complexity into separate, easily interchangeable classes.

The Problem: Calculating VAT for Different Countries

Let’s assume that we are building a retail application that needs to calculate the VAT for different countries. Each country has its own VAT rate and rules:

  • Portugal (PT): 23% VAT
  • France (FR): 20% VAT
  • Spain (SP): 21% VAT

Instead of hardcoding these rules, we’ll use the Strategy Pattern to encapsulate each VAT calculation in its own class.

Step 1: Define the Strategy Interface

We start by defining an interface IVatStrategy, which will declare the method CalculateVat().

public interface IVatStrategy
{
    decimal CalculateVat(decimal amount);
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement the Strategy Classes

Next, we implement the strategy for each country.

Portugal VAT Strategy:

public class PortugalVatStrategy : IVatStrategy
{
    public decimal CalculateVat(decimal amount)
    {
        return amount * 0.23m;
    }
}
Enter fullscreen mode Exit fullscreen mode

France VAT Strategy:

public class FranceVatStrategy : IVatStrategy
{
    public decimal CalculateVat(decimal amount)
    {
        return amount * 0.20m;
    }
}
Enter fullscreen mode Exit fullscreen mode

Spain VAT Strategy:

public class SpainVatStrategy : IVatStrategy
{
    public decimal CalculateVat(decimal amount)
    {
        return amount * 0.21m;
    }
}
Enter fullscreen mode Exit fullscreen mode

Each class adheres to the IVatStrategy interface, providing its own implementation of the CalculateVat method.

Step 3: The Context Class

The context class is responsible for using the strategy. It doesn’t care about the specific implementation of the VAT calculation; it simply relies on the strategy interface.

public class VatCalculator
{
    private IVatStrategy _vatStrategy;

    public VatCalculator(IVatStrategy vatStrategy)
    {
        _vatStrategy = vatStrategy;
    }

    public decimal CalculateVat(decimal amount)
    {
        return _vatStrategy.CalculateVat(amount);
    }
}
Enter fullscreen mode Exit fullscreen mode

This class takes a strategy as a parameter and delegates the VAT calculation to the strategy.

Step 4: Client Code

Now, we can use the VatCalculator class in our client code to calculate VAT for any country.

class Program
{
    static void Main(string[] args)
    {
        decimal amount = 100.00m;

        // Portugal VAT
        VatCalculator vatCalculator = new VatCalculator(new PortugalVatStrategy());
        Console.WriteLine("VAT in Portugal: " + vatCalculator.CalculateVat(amount));

        // France VAT
        vatCalculator = new VatCalculator(new FranceVatStrategy());
        Console.WriteLine("VAT in France: " + vatCalculator.CalculateVat(amount));

        // Spain VAT
        vatCalculator = new VatCalculator(new SpainVatStrategy());
        Console.WriteLine("VAT in Spain: " + vatCalculator.CalculateVat(amount));
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

VAT in Portugal: 23.00
VAT in France: 20.00
VAT in Spain: 21.00
Enter fullscreen mode Exit fullscreen mode

Why the Strategy Pattern Is Beneficial

  1. Extensibility: Adding a new country with a different VAT rate is as simple as creating a new class that implements IVatStrategy. The client code remains unaffected.
  2. Readability: The code is cleaner because the VAT logic is encapsulated in separate classes rather than cluttering the main code with conditionals.
  3. Maintainability: If a VAT rate changes, you only need to modify the relevant strategy class.

Conclusion

The Strategy Pattern allows for more flexible and maintainable code by decoupling algorithms from the context where they are used. In our VAT example, each country’s VAT calculation is encapsulated in its own strategy class, making it easy to add or modify countries without affecting the rest of the application. This pattern is particularly useful when you have multiple algorithms for a task and need to switch between them seamlessly.

Top comments (0)