Design Patterns — Strategy
The Strategy Design Pattern is a Behavioral design pattern that defines a family of algorithms, encapsulating each of them in a dedicated class, and making them interchangeable. With that, they ctan be replaced or modified independently of the client code that uses it, promoting code reuse, flexibility, and easier maintenance. This is one of the Gang of Four (GoF) Design Patterns, and is commonly used in many projects. In this article, I present how to implement this pattern.
This pattern allows you to extract the behaviour of an object into separate classes that can be selected/switched at runtime. Some classes that represent different strategies are created, as well as a context class whose behaviour varies according to its strategy class. For example, consider a payment scenario where you can have different types of payment methods. In this case, you can have a PaymentContext class, and a series of classes representing different payment methods (Credit card, PayPal, etc).
For demonstration purposes, I created a console application with .NET 8. which will print a message saying which payment method was executed. The complete code can be found on my GitHub.
Implementing the Strategy Design Pattern
The first step to implement this pattern is to create the strategy interface, which defines the contract for all concrete payment classes. This is the IPaymentStrategy
:
public interface IPaymentStrategy
{
void ProcessPayment(double amount);
}
Next, we create the Context class, which in this example is the PaymentContext
:
public class PaymentContext
{
private IPaymentStrategy _payment;
public PaymentContext(IPaymentStrategy payment)
{
_payment = payment;
}
public void ProcessPayment(double amount)
{
_payment.ProcessPayment(amount);
}
public void SetStrategy(IPaymentStrategy payment)
{
_payment = payment;
}
}
This class contains:
- The constructor, which receives the
IPaymentStrategy
interface. - A private property of type
IPaymentStrategy
- The
ProcessPayment
method, which executes the ProcessPayment. - The
SetStrategy
method, that can be used when you need to switch between payment methods dynamically at runtime (based on user input or other runtime conditions for example), allowing you to achieve that without needing to create new PaymentContext instances — in case you don’t need to have this behaviour, you do not need to implement this method.
Now we can create the concrete payment strategies that implement the IPaymentStrategy
interface. For this demo, I created these three classes:
public class CreditCardPayment : IPaymentStrategy
{
public void ProcessPayment(double amount)
{
Console.WriteLine($"Processing Credit Card payment of {amount} euros.");
}
}
public class PayPalPayment : IPaymentStrategy
{
public void ProcessPayment(double amount)
{
Console.WriteLine($"Processing PayPal payment of {amount} euros.");
}
}
public class BitcoinPayment : IPaymentStrategy
{
public void ProcessPayment(double amount)
{
Console.WriteLine($"Processing Bitcoin payment of {amount} euros.");
}
}
Now you can initialise a new PaymentContext
instance with the associated payment method class:
- On line 3, the variable for the PaymentContext is defined.
- On line 4, the variable for the amount that is going to be used for the payment is defined.
- On line 7, a new instance of
PaymentContext
class is created, and it is associated with a concrete payment strategy for Credit Card, and on line 8 the ProcessPayment method is executed. - On lines 11 and 15, a new instance of
PaymentContext
class is created, for PayPal and Bitcoin payment methods.
The output of this method is:
Processing Credit Card payment of 100 euros.
Processing PayPal payment of 100 euros.
Processing Bitcoin payment of 100 euros.
It’s also possible to achieve the same result, without creating multiple instances of the PaymentContext
. For that, you can use the SetStrategy
method that was previously created. For example:
- On lines 3 and 4 the variables are defined.
- On line 7, a new instance of
PaymentContext
is created, associated with a concrete payment strategy for Credit Card (similar as the previous example). - On lines 11 and 15, instead of creating a new instance of
PaymentContext
, it is now switching the payment method strategy for PayPal and Bitcoin, without creating a new instance of the class.
The output of this method is:
Processing Credit Card payment of 100 euros.
Processing PayPal payment of 100 euros.
Processing Bitcoin payment of 100 euros.
Conclusion
With the Strategy pattern, you can encapsulate your code into separate classes and make them interchangeable at runtime, promoting flexibility, modularity and code reusability. This pattern applies the Single Responsibility and the Open-Closed Principles from the SOLID principles, as demonstrated in this example, if you need to perform some change in a specific payment method, you only need to change the specific class, and in case you need to add a new payment method, you don’t need to touch existent code, instead you are going to create a new payment method class.
This is the link for the project in GitHub: https://github.com/henriquesd/StrategyDesignPattern
If you like this demo, I kindly ask you to give a ⭐️ in the repository.
Thanks for reading!