Introduction to the Strategy Pattern

Introduction to the Strategy Pattern

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.

What You'll Learn

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:

#include <iostream>
#include <string>

class PaymentStrategy {
public:
    virtual ~PaymentStrategy() = default;
    virtual void pay(int amount) = 0;
};

class CreditCardStrategy : public PaymentStrategy {
public:
    CreditCardStrategy(const std::string& cardNumber) : cardNumber(cardNumber) {}

    void pay(int amount) override {
        std::cout << "Paid " << amount << " using Credit Card: " << cardNumber << std::endl;
    }

private:
    std::string cardNumber;
};

class PayPalStrategy : public PaymentStrategy {
public:
    PayPalStrategy(const std::string& email) : email(email) {}

    void pay(int amount) override {
        std::cout << "Paid " << amount << " using PayPal: " << email << std::endl;
    }

private:
    std::string email;
};

Next, we will create a ShoppingCart class that can set a payment strategy and use it to perform the payment operation:

class ShoppingCart {
public:
    void setPaymentStrategy(PaymentStrategy* strategy) {
        this->strategy = strategy;
    }

    void checkout(int amount) {
        if (strategy) {
            strategy->pay(amount);
        } else {
            std::cout << "No payment strategy set." << std::endl;
        }
    }

private:
    PaymentStrategy* strategy = nullptr;
};

Finally, we will demonstrate how to use the ShoppingCart class with different payment strategies:

int main() {
    ShoppingCart cart;

    CreditCardStrategy creditCard("1234-5678-9876-5432");
    PayPalStrategy payPal("user@example.com");

    cart.setPaymentStrategy(&creditCard);
    cart.checkout(100);

    cart.setPaymentStrategy(&payPal);
    cart.checkout(200);

    return 0;
}

Let's analyze the key components of the Strategy Pattern through this example:

  • Strategy Interface (PaymentStrategy): An interface that defines a common method (in this case, pay) for all concrete strategies.
  • Concrete Strategies (CreditCardStrategy, PayPalStrategy): Classes that implement the PaymentStrategy interface, providing specific implementations of the pay method.
  • Context (ShoppingCart): The class that uses a PaymentStrategy object. This class can set the strategy at runtime and use it to perform its payment operations.
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal