BehavioralC++verifiedVerified
Strategy Pattern in C++
Defines a family of algorithms, encapsulates each one, and makes them interchangeable so the algorithm can vary independently from the clients that use it.
How to Implement the Strategy Pattern in C++
1Step 1: Define the strategy as a callable type
using SortStrategy = std::function<void(std::vector<int>&)>;2Step 2: Concrete strategies
SortStrategy bubbleSort = [](std::vector<int>& v) {
for (size_t i = 0; i < v.size(); ++i)
for (size_t j = 0; j + 1 < v.size() - i; ++j)
if (v[j] > v[j + 1]) std::swap(v[j], v[j + 1]);
};
SortStrategy stdSort = [](std::vector<int>& v) {
std::sort(v.begin(), v.end());
};3Step 3: Context that uses a strategy
class Sorter {
SortStrategy strategy_;
public:
explicit Sorter(SortStrategy strategy) : strategy_(std::move(strategy)) {}
void setStrategy(SortStrategy strategy) { strategy_ = std::move(strategy); }
void sort(std::vector<int>& data) { strategy_(data); }
};4Step 4: Swap strategies at runtime
int main() {
std::vector<int> data = {5, 2, 8, 1, 9};
Sorter sorter(bubbleSort);
sorter.sort(data);
for (int x : data) std::cout << x << " ";
std::cout << "\n";
data = {5, 2, 8, 1, 9};
sorter.setStrategy(stdSort);
sorter.sort(data);
for (int x : data) std::cout << x << " ";
std::cout << "\n";
}#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>
#include <format>
#include <cmath>
#include <stdexcept>
#include <concepts>
// [step] Define the pricing strategy interface with concepts
struct PricingInput {
double basePrice;
int quantity;
double customerTier; // 0.0 = basic, 1.0 = VIP
bool isHoliday;
};
struct PricingResult {
double finalPrice;
double discount;
std::string strategyName;
};
template <typename T>
concept PricingStrategy = requires(T t, PricingInput input) {
{ t.calculate(input) } -> std::same_as<PricingResult>;
{ t.name() } -> std::convertible_to<std::string>;
};
// [step] Concrete strategies
class StandardPricing {
public:
PricingResult calculate(const PricingInput& input) const {
double total = input.basePrice * input.quantity;
return {total, 0.0, name()};
}
std::string name() const { return "Standard"; }
};
class BulkDiscountPricing {
double threshold_;
double discountPct_;
public:
BulkDiscountPricing(double threshold = 10, double pct = 0.15)
: threshold_(threshold), discountPct_(pct) {}
PricingResult calculate(const PricingInput& input) const {
double total = input.basePrice * input.quantity;
double discount = input.quantity >= threshold_ ? total * discountPct_ : 0;
return {total - discount, discount, name()};
}
std::string name() const {
return std::format("BulkDiscount({}% over {} items)",
static_cast<int>(discountPct_ * 100),
static_cast<int>(threshold_));
}
};
class TieredPricing {
public:
PricingResult calculate(const PricingInput& input) const {
double total = input.basePrice * input.quantity;
double discount = total * input.customerTier * 0.20;
if (input.isHoliday) discount += total * 0.05;
return {total - discount, discount, name()};
}
std::string name() const { return "Tiered"; }
};
// [step] Context with type-erased strategy using std::function
class PricingEngine {
std::function<PricingResult(const PricingInput&)> strategy_;
std::string strategyName_;
public:
template <PricingStrategy S>
void setStrategy(S strategy) {
strategyName_ = strategy.name();
strategy_ = [s = std::move(strategy)](const PricingInput& input) {
return s.calculate(input);
};
}
PricingResult price(const PricingInput& input) const {
if (!strategy_)
throw std::runtime_error("No pricing strategy configured");
return strategy_(input);
}
const std::string& currentStrategy() const { return strategyName_; }
};
// [step] Demonstrate runtime strategy switching
int main() {
PricingEngine engine;
PricingInput order{29.99, 15, 0.8, true};
engine.setStrategy(StandardPricing{});
auto r1 = engine.price(order);
std::cout << std::format("[{}] price={:.2f}, discount={:.2f}\n",
r1.strategyName, r1.finalPrice, r1.discount);
engine.setStrategy(BulkDiscountPricing{10, 0.15});
auto r2 = engine.price(order);
std::cout << std::format("[{}] price={:.2f}, discount={:.2f}\n",
r2.strategyName, r2.finalPrice, r2.discount);
engine.setStrategy(TieredPricing{});
auto r3 = engine.price(order);
std::cout << std::format("[{}] price={:.2f}, discount={:.2f}\n",
r3.strategyName, r3.finalPrice, r3.discount);
}Strategy Pattern Architecture
hourglass_empty
Rendering diagram...
lightbulb
Strategy Pattern in the Real World
“Consider a GPS app offering route options: fastest, shortest, or avoid tolls. The destination is the same, but the navigation algorithm changes based on your preference. The app (context) simply hands the journey off to whichever routing strategy you selected; you can switch strategies mid-trip without the app needing to change its structure.”