Welcome back! We are continuing our journey through Behavioral Patterns in C++. In previous lessons, we explored the Command and Observer patterns, focusing on object communication and state changes. Now, we will delve into the Strategy Pattern.
In this lesson, you will learn how to implement the Strategy Pattern in C++. We will break down the pattern into manageable parts and illustrate its practical application through a clear example.
Consider a scenario where you have a ShoppingCart class that can handle payments through different methods, such as credit cards or PayPal. Using the Strategy Pattern, we can encapsulate these payment methods into separate classes and have the ShoppingCart class use any of these strategies interchangeably.
Here is a snippet of the code we will be working with:
We will start by defining the PaymentStrategy interface, which declares a common method for all payment strategies. Then, we will create concrete strategies such as CreditCardStrategy and PayPalStrategy that implement this interface:
C++1#include <iostream> 2#include <string> 3 4class PaymentStrategy { 5public: 6 virtual ~PaymentStrategy() = default; 7 virtual void pay(int amount) = 0; 8}; 9 10class CreditCardStrategy : public PaymentStrategy { 11public: 12 CreditCardStrategy(const std::string& cardNumber) : cardNumber(cardNumber) {} 13 14 void pay(int amount) override { 15 std::cout << "Paid " << amount << " using Credit Card: " << cardNumber << std::endl; 16 } 17 18private: 19 std::string cardNumber; 20}; 21 22class PayPalStrategy : public PaymentStrategy { 23public: 24 PayPalStrategy(const std::string& email) : email(email) {} 25 26 void pay(int amount) override { 27 std::cout << "Paid " << amount << " using PayPal: " << email << std::endl; 28 } 29 30private: 31 std::string email; 32};
Next, we will create a ShoppingCart class that can set a payment strategy and use it to perform the payment operation:
C++1class ShoppingCart { 2public: 3 void setPaymentStrategy(PaymentStrategy* strategy) { 4 this->strategy = strategy; 5 } 6 7 void checkout(int amount) { 8 if (strategy) { 9 strategy->pay(amount); 10 } else { 11 std::cout << "No payment strategy set." << std::endl; 12 } 13 } 14 15private: 16 PaymentStrategy* strategy = nullptr; 17};
Finally, we will demonstrate how to use the ShoppingCart class with different payment strategies:
C++1int main() { 2 ShoppingCart cart; 3 4 CreditCardStrategy creditCard("1234-5678-9876-5432"); 5 PayPalStrategy payPal("user@example.com"); 6 7 cart.setPaymentStrategy(&creditCard); 8 cart.checkout(100); 9 10 cart.setPaymentStrategy(&payPal); 11 cart.checkout(200); 12 13 return 0; 14}
Let's analyze the key components of the Strategy Pattern through this example:
PaymentStrategy
): An interface that defines a common method (in this case, pay
) for all concrete strategies.CreditCardStrategy
, PayPalStrategy
): Classes that implement the PaymentStrategy
interface, providing specific implementations of the pay
method.ShoppingCart
): The class that uses a PaymentStrategy
object. This class can set the strategy at runtime and use it to perform its payment operations.The Strategy Pattern is ideal for scenarios where multiple algorithms or behaviors can be used interchangeably. Some common use cases include:
Pros
Cons
By weighing these pros and cons, you can determine whether the Strategy Pattern is the best fit for your specific application requirements.
Understanding the Strategy Pattern is crucial because it promotes flexibility and reusability in your code. Instead of hardcoding multiple algorithms within a class, you can encapsulate them into separate strategy classes. This makes your code more maintainable and scalable.
Consider a real-world example: an e-commerce platform. One customer might prefer to pay using a credit card, while another might choose PayPal. With the Strategy Pattern, you can easily switch payment methods without altering the underlying business logic of the shopping cart.
Exciting, right? By mastering the Strategy Pattern, you'll be equipped to build systems that can adapt to varying requirements with minimal changes to the codebase. Let's move on to the practice section and see these concepts in action!