In the realm of software design, achieving flexibility and maintainability is a constant pursuit. One design pattern that elegantly addresses these concerns is the Strategy Pattern. This pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. In this blog post, we’ll delve into the Strategy Pattern using a practical example in C#.
Understanding the Example
Let’s explore a scenario involving a Shop
class. This shop allows customers to pay using different payment gateways, such as Google Pay and Apple Pay. The Strategy Pattern comes into play by enabling the Shop
to dynamically change its payment strategy without altering its core structure.
namespace Strategy
{
public class Shop
{
private ICheckOut _checkOut;
public Shop(ICheckOut checkOut)
{
this._checkOut = checkOut;
}
public void ChangeCheckOut(ICheckOut check)
{
_checkOut = check;
}
public string Pay(double price)
{
return _checkOut.PayWith(price);
}
}
}
namespace Strategy
{
public interface ICheckOut
{
string PayWith(double price);
}
}
namespace Strategy
{
public class CheckOutWithGoogle : ICheckOut
{
public string PayWith(double price)
{
return "pay with Google OK";
}
}
}
namespace Strategy
{
public class CheckOutWithApple : ICheckOut
{
public string PayWith(double price)
{
return "pay with Apple OK";
}
}
}
Breaking Down the Components
- Shop Class:
- The
Shop
class contains a private_checkOut
field of typeICheckOut
, representing the payment strategy. - It has a constructor to set the initial payment strategy and methods to change the payment strategy (
ChangeCheckOut
) and initiate payment (Pay
).
- The
- ICheckOut Interface:
- The
ICheckOut
interface declares a methodPayWith
that takes the payment amount and returns a string indicating the success of the payment.
- The
- CheckOutWithGoogle and CheckOutWithApple Classes:
- Classes implementing the
ICheckOut
interface with specific payment logic for Google Pay and Apple Pay.
- Classes implementing the
Using the Strategy Pattern
Now, let’s see how the Strategy Pattern empowers the Shop
class:
// Creating a Shop with Google Pay
var shop = new Shop(new CheckOutWithGoogle());
var result = shop.Pay(100.0); // "pay with Google OK"
// Changing the payment strategy to Apple Pay
shop.ChangeCheckOut(new CheckOutWithApple());
result = shop.Pay(150.0); // "pay with Apple OK"
Advantages of the Strategy Pattern
- Flexibility:
- The
Shop
class can dynamically switch between different payment strategies, allowing for flexibility in adapting to changing requirements.
- The
- Maintainability:
- Adding new payment strategies (e.g., for additional payment gateways) is seamless without modifying existing code.
- Testability:
- Each payment strategy can be tested independently, ensuring robustness.
Conclusion
The Strategy Pattern proves to be a valuable asset in designing software systems that require flexibility in algorithm selection. By encapsulating algorithms into separate classes, the Strategy Pattern promotes clean, maintainable, and extensible code. In the context of the Shop
class, the ability to dynamically switch payment strategies demonstrates the pattern’s prowess in simplifying complex scenarios. Integrate the Strategy Pattern into your design toolkit to master flexibility and elevate your software design practices.
Happy coding!