The Strategy pattern is one of the simplest and most useful design patterns. It lets you swap out different algorithms or behaviors at runtime.

The Strategy pattern says: “Define a family of algorithms, encapsulate each one, and make them interchangeable”. Here’s how it works with a simple shopping cart example:

  1. Strategy Interface (PaymentStrategy) - Defines what all strategies must implement
  2. Concrete Strategies (CreditCard, PayPal) - Different implementations of the interface
  3. Context (ShoppingCart) - Uses the strategy without knowing which specific one

The magic is that ShoppingCart doesn’t care how the payment is processed. It just calls pay() and lets the strategy handle the details.

#include <iostream>
#include <memory>
using namespace std;

// Strategy Interface - defines what all payment methods must do
class PaymentStrategy {
public:
    virtual ~PaymentStrategy() = default;
    virtual void pay(double amount) = 0;
};

// Concrete Strategies - different ways to pay
class CreditCard : public PaymentStrategy {
public:
    void pay(double amount) override {
        cout << "Paid $" << amount << " with Credit Card" << endl;
    }
};

class PayPal : public PaymentStrategy {
public:
    void pay(double amount) override {
        cout << "Paid $" << amount << " with PayPal" << endl;
    }
};

// Context - uses the strategy
class ShoppingCart {
private:
    unique_ptr<PaymentStrategy> strategy_;
    double total_;

public:
    ShoppingCart(double total) : total_(total) {}

    void setPaymentMethod(unique_ptr<PaymentStrategy> strategy) {
        strategy_ = std::move(strategy);
    }

    void checkout() {
        if (strategy_) {
            strategy_->pay(total_);
        } else {
            cout << "No payment method selected!" << endl;
        }
    }
};

int main() {
    ShoppingCart cart(99.99);

    // Choose credit card
    cart.setPaymentMethod(make_unique<CreditCard>());
    cart.checkout();

    // Switch to PayPal
    cart.setPaymentMethod(make_unique<PayPal>());
    cart.checkout();

    return 0;
}