策略模式

介绍

目的: 定义一系列的算法(行为),把它们一个个封装起来,并且使它们可以互替换(继承接口).

关键: 实现同一个接口.

优点:

  1. 算法之间可以互相替换;
  2. 可以避免多重条件判断;
  3. 扩展性良好.

缺点:

  1. 策略类会比较多;
  2. 所有策略都需要对外暴露.

使用场景:

  1. 一个对象可能存在多种行为,需要使用多重条件判断时;
  2. 系统需要在几种算法中选择一种.

案例

基础示例 - 数学运算

#include <iostream>
#include <memory>

//接口类
class Strategy{
public:
virtual int doOperate(const int a, const int b) = 0;
};

//算法实现1
class StrategyAdd : public Strategy{
public:
int doOperate(const int a, const int b) override {
return a+b;
}
};

//算法实2
class StrategySub : public Strategy{
public:
int doOperate(const int a, const int b) override {
return a-b;
}
};

//条件选择
class Context {
public:
Context(std::shared_ptr<Strategy> Strategy) : Strategy_(Strategy){}

std::shared_ptr<Strategy> GetStrategy() {
return Strategy_;
}

void SetStrategy(std::shared_ptr<Strategy> Strategy) {
Strategy_ = Strategy;
}

int doOperate(const int a, const int b) {
return Strategy_->doOperate(a, b);
}

private:
std::shared_ptr<Strategy> Strategy_;
};

int main() {
Context context(std::make_shared<StrategyAdd>());
std::cout << context.doOperate(10, 100) << std::endl;

context.SetStrategy(std::make_shared<StrategySub>());
std::cout << context.doOperate(10, 100) << std::endl;
return 0;
}

实际应用案例 - 支付处理系统

#include <iostream>
#include <memory>
#include <string>
#include <vector>

// 支付策略接口
class PaymentStrategy {
public:
virtual ~PaymentStrategy() = default;
virtual bool processPayment(double amount) = 0;
virtual std::string getPaymentMethod() const = 0;
};

// 信用卡支付策略
class CreditCardPayment : public PaymentStrategy {
private:
std::string cardNumber_;
std::string holderName_;

public:
CreditCardPayment(const std::string& cardNumber, const std::string& holderName)
: cardNumber_(cardNumber), holderName_(holderName) {}

bool processPayment(double amount) override {
std::cout << "Processing credit card payment of $" << amount
<< " for " << holderName_
<< " (Card: ****" << cardNumber_.substr(cardNumber_.length()-4)
<< ")" << std::endl;
// 模拟支付处理逻辑
return amount > 0 && amount <= 10000; // 假设信用卡限额10000
}

std::string getPaymentMethod() const override {
return "Credit Card";
}
};

// PayPal支付策略
class PayPalPayment : public PaymentStrategy {
private:
std::string email_;

public:
PayPalPayment(const std::string& email) : email_(email) {}

bool processPayment(double amount) override {
std::cout << "Processing PayPal payment of $" << amount
<< " for " << email_ << std::endl;
// 模拟PayPal支付处理
return amount > 0 && amount <= 5000; // PayPal限额5000
}

std::string getPaymentMethod() const override {
return "PayPal";
}
};

// 银行转账支付策略
class BankTransferPayment : public PaymentStrategy {
private:
std::string bankAccount_;

public:
BankTransferPayment(const std::string& bankAccount)
: bankAccount_(bankAccount) {}

bool processPayment(double amount) override {
std::cout << "Processing bank transfer of $" << amount
<< " from account " << bankAccount_ << std::endl;
// 银行转账通常没有限额但处理时间长
return amount > 0;
}

std::string getPaymentMethod() const override {
return "Bank Transfer";
}
};

// 支付上下文
class PaymentProcessor {
private:
std::shared_ptr<PaymentStrategy> strategy_;

public:
void setPaymentStrategy(std::shared_ptr<PaymentStrategy> strategy) {
strategy_ = strategy;
}

bool processOrder(double amount) {
if (!strategy_) {
std::cout << "No payment method selected!" << std::endl;
return false;
}

std::cout << "Using " << strategy_->getPaymentMethod()
<< " payment method." << std::endl;
return strategy_->processPayment(amount);
}
};

// 使用示例
int main() {
PaymentProcessor processor;

// 小额支付用PayPal
auto paypal = std::make_shared<PayPalPayment>("user@example.com");
processor.setPaymentStrategy(paypal);
processor.processOrder(299.99);

std::cout << "\n" << std::string(50, '-') << "\n" << std::endl;

// 大额支付用银行转账
auto bankTransfer = std::make_shared<BankTransferPayment>("123456789");
processor.setPaymentStrategy(bankTransfer);
processor.processOrder(15000.00);

std::cout << "\n" << std::string(50, '-') << "\n" << std::endl;

// 中等金额用信用卡
auto creditCard = std::make_shared<CreditCardPayment>("1234567890123456", "John Doe");
processor.setPaymentStrategy(creditCard);
processor.processOrder(1999.99);

return 0;
}

数据排序策略示例

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <chrono>

// 排序策略接口
class SortStrategy {
public:
virtual ~SortStrategy() = default;
virtual void sort(std::vector<int>& data) = 0;
virtual std::string getName() const = 0;
};

// 快速排序策略
class QuickSortStrategy : public SortStrategy {
private:
void quickSort(std::vector<int>& arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}

int partition(std::vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = (low - 1);

for (int j = low; j <= high - 1; j++) {
if (arr[j] < pivot) {
i++;
std::swap(arr[i], arr[j]);
}
}
std::swap(arr[i + 1], arr[high]);
return (i + 1);
}

public:
void sort(std::vector<int>& data) override {
if (!data.empty()) {
quickSort(data, 0, data.size() - 1);
}
}

std::string getName() const override {
return "Quick Sort";
}
};

// 归并排序策略
class MergeSortStrategy : public SortStrategy {
private:
void mergeSort(std::vector<int>& arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}

void merge(std::vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;

std::vector<int> leftArr(n1), rightArr(n2);

for (int i = 0; i < n1; i++)
leftArr[i] = arr[left + i];
for (int j = 0; j < n2; j++)
rightArr[j] = arr[mid + 1 + j];

int i = 0, j = 0, k = left;

while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
arr[k] = leftArr[i];
i++;
} else {
arr[k] = rightArr[j];
j++;
}
k++;
}

while (i < n1) {
arr[k] = leftArr[i];
i++;
k++;
}

while (j < n2) {
arr[k] = rightArr[j];
j++;
k++;
}
}

public:
void sort(std::vector<int>& data) override {
if (!data.empty()) {
mergeSort(data, 0, data.size() - 1);
}
}

std::string getName() const override {
return "Merge Sort";
}
};

// STL排序策略(通常是introsort,混合算法)
class STLSortStrategy : public SortStrategy {
public:
void sort(std::vector<int>& data) override {
std::sort(data.begin(), data.end());
}

std::string getName() const override {
return "STL Sort";
}
};

// 排序上下文
class Sorter {
private:
std::shared_ptr<SortStrategy> strategy_;

public:
void setStrategy(std::shared_ptr<SortStrategy> strategy) {
strategy_ = strategy;
}

void performSort(std::vector<int>& data) {
if (!strategy_) {
std::cout << "No sorting strategy selected!" << std::endl;
return;
}

auto start = std::chrono::high_resolution_clock::now();
strategy_->sort(data);
auto end = std::chrono::high_resolution_clock::now();

auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << strategy_->getName() << " completed in "
<< duration.count() << " microseconds" << std::endl;
}
};

现代C++特性示例

使用模板和Lambda表达式

#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <map>
#include <vector>
#include <algorithm>

// 模板化策略接口
template<typename Input, typename Output>
class Strategy {
public:
virtual ~Strategy() = default;
virtual Output execute(const Input& input) = 0;
};

// 使用std::function的轻量级策略系统
template<typename Input, typename Output>
class FunctionStrategy {
private:
std::function<Output(const Input&)> strategy_func_;
std::string name_;

public:
FunctionStrategy(std::function<Output(const Input&)> func, const std::string& name)
: strategy_func_(func), name_(name) {}

Output execute(const Input& input) {
return strategy_func_(input);
}

const std::string& getName() const { return name_; }
};

// 策略上下文 - 使用模板
template<typename Input, typename Output>
class StrategyContext {
private:
std::shared_ptr<Strategy<Input, Output>> strategy_;

public:
void setStrategy(std::shared_ptr<Strategy<Input, Output>> strategy) {
strategy_ = strategy;
}

Output executeStrategy(const Input& input) {
if (!strategy_) {
throw std::runtime_error("No strategy set");
}
return strategy_->execute(input);
}
};

// 字符串处理策略示例
class StringProcessor {
private:
std::map<std::string, std::function<std::string(const std::string&)>> strategies_;

public:
StringProcessor() {
// 使用Lambda表达式定义策略
strategies_["uppercase"] = [](const std::string& input) {
std::string result = input;
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
return result;
};

strategies_["lowercase"] = [](const std::string& input) {
std::string result = input;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
};

strategies_["reverse"] = [](const std::string& input) {
std::string result = input;
std::reverse(result.begin(), result.end());
return result;
};

strategies_["capitalize"] = [](const std::string& input) {
if (input.empty()) return input;
std::string result = input;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
result[0] = std::toupper(result[0]);
return result;
};
}

std::string process(const std::string& input, const std::string& strategy_name) {
auto it = strategies_.find(strategy_name);
if (it != strategies_.end()) {
return it->second(input);
}
throw std::invalid_argument("Unknown strategy: " + strategy_name);
}

void addStrategy(const std::string& name, std::function<std::string(const std::string&)> strategy) {
strategies_[name] = strategy;
}

std::vector<std::string> getAvailableStrategies() const {
std::vector<std::string> names;
for (const auto& pair : strategies_) {
names.push_back(pair.first);
}
return names;
}
};

// 使用示例
int main() {
StringProcessor processor;

std::string text = "Hello World!";

// 使用预定义策略
std::cout << "Original: " << text << std::endl;
std::cout << "Uppercase: " << processor.process(text, "uppercase") << std::endl;
std::cout << "Lowercase: " << processor.process(text, "lowercase") << std::endl;
std::cout << "Reverse: " << processor.process(text, "reverse") << std::endl;
std::cout << "Capitalize: " << processor.process(text, "capitalize") << std::endl;

// 动态添加新的策略
processor.addStrategy("remove_spaces", [](const std::string& input) {
std::string result;
std::copy_if(input.begin(), input.end(), std::back_inserter(result),
[](char c) { return c != ' '; });
return result;
});

std::cout << "Remove spaces: " << processor.process(text, "remove_spaces") << std::endl;

// 列出所有可用策略
std::cout << "\nAvailable strategies: ";
auto strategies = processor.getAvailableStrategies();
for (const auto& strategy : strategies) {
std::cout << strategy << " ";
}
std::cout << std::endl;

return 0;
}

使用C++20概念的策略模式

#include <iostream>
#include <concepts>
#include <memory>
#include <type_traits>

// C++20概念定义策略接口
template<typename T, typename Input, typename Output>
concept StrategyType = requires(T strategy, const Input& input) {
{ strategy.execute(input) } -> std::same_as<Output>;
{ strategy.getName() } -> std::convertible_to<std::string>;
};

// 基础策略接口
template<typename Input, typename Output>
class BaseStrategy {
public:
virtual ~BaseStrategy() = default;
virtual Output execute(const Input& input) = 0;
virtual std::string getName() const = 0;
};

// 数学运算策略
class MathStrategy : public BaseStrategy<std::pair<int, int>, int> {
public:
virtual ~MathStrategy() = default;
};

class AddStrategy : public MathStrategy {
public:
int execute(const std::pair<int, int>& input) override {
return input.first + input.second;
}

std::string getName() const override {
return "Addition";
}
};

class MultiplyStrategy : public MathStrategy {
public:
int execute(const std::pair<int, int>& input) override {
return input.first * input.second;
}

std::string getName() const override {
return "Multiplication";
}
};

// 现代C++策略上下文,使用概念约束
template<typename Strategy, typename Input, typename Output>
requires StrategyType<Strategy, Input, Output>
class ModernStrategyContext {
private:
std::unique_ptr<Strategy> strategy_;

public:
template<typename... Args>
void setStrategy(Args&&... args) {
strategy_ = std::make_unique<Strategy>(std::forward<Args>(args)...);
}

Output executeStrategy(const Input& input) {
if (!strategy_) {
throw std::runtime_error("No strategy set");
}

std::cout << "Executing strategy: " << strategy_->getName() << std::endl;
return strategy_->execute(input);
}
};

// 使用完美转发的工厂函数
template<typename Strategy, typename... Args>
auto makeStrategy(Args&&... args) {
return std::make_unique<Strategy>(std::forward<Args>(args)...);
}

使用变参模板的策略组合

#include <iostream>
#include <tuple>
#include <utility>
#include <type_traits>

// 策略组合器 - 可以组合多个策略
template<typename... Strategies>
class StrategyComposer {
private:
std::tuple<Strategies...> strategies_;

public:
StrategyComposer(Strategies... strategies) : strategies_(strategies...) {}

template<typename Input>
auto execute(const Input& input) {
return executeImpl(input, std::index_sequence_for<Strategies...>{});
}

private:
template<typename Input, size_t... Is>
auto executeImpl(const Input& input, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is>(strategies_).execute(input)...);
}
};

// 管道式策略执行器
template<typename Input, typename... Strategies>
auto executePipeline(Input&& input, Strategies&&... strategies) {
return (strategies.execute(std::forward<Input>(input)), ...);
}

// 示例:字符串处理管道
struct UppercaseStrategy {
std::string execute(const std::string& input) {
std::string result = input;
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
return result;
}
};

struct TrimStrategy {
std::string execute(const std::string& input) {
size_t start = input.find_first_not_of(" \t");
if (start == std::string::npos) return "";
size_t end = input.find_last_not_of(" \t");
return input.substr(start, end - start + 1);
}
};

性能分析与最佳实践

性能考虑

虚函数调用开销

策略模式使用虚函数,存在一定的性能开销:

#include <iostream>
#include <chrono>
#include <memory>

// 传统虚函数方式
class VirtualStrategy {
public:
virtual ~VirtualStrategy() = default;
virtual int compute(int x) = 0;
};

class ConcreteVirtual : public VirtualStrategy {
public:
int compute(int x) override {
return x * x + 2 * x + 1;
}
};

// 模板方式(编译期多态)
template<typename Strategy>
class TemplateContext {
private:
Strategy strategy_;

public:
int compute(int x) {
return strategy_.compute(x);
}
};

struct ConcreteTemplate {
int compute(int x) {
return x * x + 2 * x + 1;
}
};

// 性能测试
void performanceTest() {
const int iterations = 10000000;

// 虚函数测试
auto virtualStrategy = std::make_unique<ConcreteVirtual>();
auto start = std::chrono::high_resolution_clock::now();

volatile int result1 = 0; // volatile防止编译器优化
for (int i = 0; i < iterations; ++i) {
result1 += virtualStrategy->compute(i);
}

auto end = std::chrono::high_resolution_clock::now();
auto virtualTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

// 模板测试
TemplateContext<ConcreteTemplate> templateContext;
start = std::chrono::high_resolution_clock::now();

volatile int result2 = 0;
for (int i = 0; i < iterations; ++i) {
result2 += templateContext.compute(i);
}

end = std::chrono::high_resolution_clock::now();
auto templateTime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

std::cout << "Virtual function time: " << virtualTime.count() << " microseconds" << std::endl;
std::cout << "Template time: " << templateTime.count() << " microseconds" << std::endl;
std::cout << "Template is " << (double)virtualTime.count() / templateTime.count()
<< "x faster" << std::endl;
}

内存管理优化

#include <memory>
#include <vector>
#include <memory_resource>

// 使用对象池减少内存分配开销
template<typename Strategy>
class StrategyPool {
private:
std::vector<std::unique_ptr<Strategy>> available_;
size_t max_size_;

public:
StrategyPool(size_t max_size = 10) : max_size_(max_size) {
available_.reserve(max_size_);
}

template<typename... Args>
std::shared_ptr<Strategy> acquire(Args&&... args) {
if (available_.empty()) {
return std::shared_ptr<Strategy>(
new Strategy(std::forward<Args>(args)...),
[this](Strategy* ptr) { this->release(std::unique_ptr<Strategy>(ptr)); }
);
}

auto strategy = std::shared_ptr<Strategy>(
available_.back().release(),
[this](Strategy* ptr) { this->release(std::unique_ptr<Strategy>(ptr)); }
);
available_.pop_back();
return strategy;
}

private:
void release(std::unique_ptr<Strategy> strategy) {
if (available_.size() < max_size_) {
available_.push_back(std::move(strategy));
}
// 如果池满了,直接删除对象
}
};

// 使用PMR(多态内存资源)优化内存分配
class PMRStrategy {
private:
std::pmr::memory_resource* resource_;
std::pmr::vector<int> data_;

public:
PMRStrategy(std::pmr::memory_resource* resource = std::pmr::get_default_resource())
: resource_(resource), data_(resource_) {}

void processData(const std::vector<int>& input) {
data_.clear();
data_.reserve(input.size());

for (int val : input) {
data_.push_back(val * 2);
}
}

const std::pmr::vector<int>& getData() const { return data_; }
};

最佳实践

1. 策略接口设计

// ✅ 好的设计:接口专一,职责明确
class CompressionStrategy {
public:
virtual ~CompressionStrategy() = default;
virtual std::vector<uint8_t> compress(const std::vector<uint8_t>& data) = 0;
virtual double getCompressionRatio() const = 0;
virtual std::string getName() const = 0;
};

// ❌ 不好的设计:接口过于宽泛
class BadStrategy {
public:
virtual void doEverything(void* data) = 0; // 过于宽泛
virtual int getResult() = 0; // 不明确的返回类型
};

2. 异常安全

#include <stdexcept>

class SafeStrategy {
public:
virtual ~SafeStrategy() = default;

// 提供强异常安全保证
virtual void execute(Data& data) {
Data backup = data; // 备份原数据
try {
executeImpl(data);
} catch (...) {
data = std::move(backup); // 回滚
throw;
}
}

protected:
virtual void executeImpl(Data& data) = 0;
};

// 使用RAII确保资源管理
class ResourceAwareStrategy {
private:
struct ResourceGuard {
void* resource;
ResourceGuard(void* r) : resource(r) {}
~ResourceGuard() { if (resource) cleanup(resource); }
ResourceGuard(const ResourceGuard&) = delete;
ResourceGuard& operator=(const ResourceGuard&) = delete;
};

public:
void execute() {
void* resource = acquire_resource();
ResourceGuard guard(resource);

// 执行策略逻辑...
// 资源会自动清理
}
};

3. 线程安全

#include <mutex>
#include <shared_mutex>
#include <atomic>

class ThreadSafeStrategyContext {
private:
mutable std::shared_mutex mutex_;
std::shared_ptr<Strategy> strategy_;
std::atomic<bool> strategy_changed_{false};

public:
void setStrategy(std::shared_ptr<Strategy> new_strategy) {
std::unique_lock<std::shared_mutex> lock(mutex_);
strategy_ = new_strategy;
strategy_changed_.store(true);
}

auto getStrategy() const {
std::shared_lock<std::shared_mutex> lock(mutex_);
return strategy_;
}

template<typename... Args>
auto executeStrategy(Args&&... args) const {
auto current_strategy = getStrategy(); // 获取当前策略的副本
if (!current_strategy) {
throw std::runtime_error("No strategy set");
}
return current_strategy->execute(std::forward<Args>(args)...);
}

bool hasStrategyChanged() const {
return strategy_changed_.exchange(false);
}
};

4. 策略工厂模式

#include <unordered_map>
#include <functional>

template<typename Strategy>
class StrategyFactory {
private:
std::unordered_map<std::string, std::function<std::unique_ptr<Strategy>()>> creators_;

public:
template<typename ConcreteStrategy, typename... Args>
void registerStrategy(const std::string& name, Args&&... args) {
creators_[name] = [args...]() -> std::unique_ptr<Strategy> {
return std::make_unique<ConcreteStrategy>(args...);
};
}

std::unique_ptr<Strategy> createStrategy(const std::string& name) {
auto it = creators_.find(name);
if (it != creators_.end()) {
return it->second();
}
throw std::invalid_argument("Unknown strategy: " + name);
}

std::vector<std::string> getAvailableStrategies() const {
std::vector<std::string> names;
names.reserve(creators_.size());

for (const auto& pair : creators_) {
names.push_back(pair.first);
}
return names;
}

bool hasStrategy(const std::string& name) const {
return creators_.find(name) != creators_.end();
}
};

// 使用示例
void demonstrateFactory() {
StrategyFactory<PaymentStrategy> factory;

// 注册不同的支付策略
factory.registerStrategy<CreditCardPayment>("credit_card", "1234567890123456", "John Doe");
factory.registerStrategy<PayPalPayment>("paypal", "user@example.com");
factory.registerStrategy<BankTransferPayment>("bank_transfer", "987654321");

// 根据配置或用户选择创建策略
std::string paymentMethod = "credit_card"; // 可能来自配置文件
auto strategy = factory.createStrategy(paymentMethod);

PaymentProcessor processor;
processor.setPaymentStrategy(std::move(strategy));
processor.processOrder(299.99);
}

5. 策略链模式

// 将多个策略串联执行
template<typename Input, typename Output = Input>
class StrategyChain {
private:
std::vector<std::unique_ptr<Strategy<Input, Output>>> strategies_;

public:
void addStrategy(std::unique_ptr<Strategy<Input, Output>> strategy) {
strategies_.push_back(std::move(strategy));
}

Output execute(Input input) {
Output result = input;
for (auto& strategy : strategies_) {
result = strategy->execute(result);
}
return result;
}

void clear() {
strategies_.clear();
}

size_t size() const {
return strategies_.size();
}
};

相关设计模式对比

与工厂模式的区别

策略模式初看和工厂模式其实是有点像的,但是细看其实区别很大:

  • 工厂模式:创建型模式,它的作用就是创建对象;策略模式:行为型模式,它的作用是让一个对象在许多行为中选择一种行为
  • 工厂模式关注对象创建,实际创建对象是被封装的,用户不可见;策略模式更多是关注行为的替换,创建对象其实是对用户可见的

状态模式 (State Pattern)

状态模式与策略模式结构相似,但意图不同:

#include <iostream>
#include <memory>

// 前向声明
class VendingMachine;

// 状态接口
class State {
public:
virtual ~State() = default;
virtual void insertCoin(VendingMachine* machine) = 0;
virtual void selectProduct(VendingMachine* machine) = 0;
virtual void dispenseProduct(VendingMachine* machine) = 0;
virtual std::string getStateName() const = 0;
};

// 等待投币状态
class WaitingState : public State {
public:
void insertCoin(VendingMachine* machine) override;
void selectProduct(VendingMachine* machine) override {
std::cout << "Please insert coin first!" << std::endl;
}
void dispenseProduct(VendingMachine* machine) override {
std::cout << "Please insert coin and select product first!" << std::endl;
}
std::string getStateName() const override {
return "Waiting for coin";
}
};

// 自动售货机上下文
class VendingMachine {
private:
std::shared_ptr<State> current_state_;
int coin_count_ = 0;

public:
VendingMachine() {
current_state_ = std::make_shared<WaitingState>();
}

void setState(std::shared_ptr<State> state) {
current_state_ = state;
std::cout << "State changed to: " << state->getStateName() << std::endl;
}

void insertCoin() { current_state_->insertCoin(this); }
void selectProduct() { current_state_->selectProduct(this); }
void dispenseProduct() { current_state_->dispenseProduct(this); }

void addCoin() { coin_count_++; }
void removeCoin() { coin_count_--; }
int getCoinCount() const { return coin_count_; }
};

// 状态模式 vs 策略模式:
// 策略模式:客户端主动选择算法,策略之间独立
// 状态模式:状态根据条件自动转换,状态间有依赖关系

模板方法模式 (Template Method Pattern)

定义算法骨架,让子类实现具体步骤:

#include <iostream>
#include <vector>

// 数据处理模板
class DataProcessor {
public:
// 模板方法 - 定义算法骨架
void processData(const std::string& source) {
std::vector<std::string> data = loadData(source);
validateData(data);
std::vector<std::string> processedData = transformData(data);
saveResults(processedData);
cleanup();
}

protected:
// 抽象方法 - 子类必须实现
virtual std::vector<std::string> loadData(const std::string& source) = 0;
virtual std::vector<std::string> transformData(const std::vector<std::string>& data) = 0;
virtual void saveResults(const std::vector<std::string>& results) = 0;

// 钩子方法 - 子类可以选择性重写
virtual void validateData(const std::vector<std::string>& data) {
std::cout << "Validating " << data.size() << " records..." << std::endl;
}

virtual void cleanup() {
std::cout << "Cleaning up resources..." << std::endl;
}
};

// CSV处理器
class CSVProcessor : public DataProcessor {
protected:
std::vector<std::string> loadData(const std::string& filename) override {
std::cout << "Loading data from CSV file: " << filename << std::endl;
return {"row1,data1", "row2,data2", "row3,data3"};
}

std::vector<std::string> transformData(const std::vector<std::string>& data) override {
std::cout << "Transforming CSV data..." << std::endl;
std::vector<std::string> result;
for (const auto& row : data) {
result.push_back("Processed: " + row);
}
return result;
}

void saveResults(const std::vector<std::string>& results) override {
std::cout << "Saving results to CSV format..." << std::endl;
for (const auto& result : results) {
std::cout << result << std::endl;
}
}
};

// 模板方法模式 vs 策略模式:
// 模板方法:定义算法结构,变化点在具体步骤
// 策略模式:整个算法都可替换

命令模式 (Command Pattern)

将请求封装为对象,支持撤销、队列等操作:

#include <iostream>
#include <memory>
#include <stack>

// 命令接口
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
virtual std::string getDescription() const = 0;
};

// 文本编辑器 (接收者)
class TextEditor {
private:
std::string content_;

public:
void insertText(const std::string& text) { content_ += text; }
void deleteText(size_t length) {
if (length <= content_.length()) {
content_.erase(content_.length() - length);
}
}
const std::string& getContent() const { return content_; }
};

// 插入文本命令
class InsertCommand : public Command {
private:
TextEditor* editor_;
std::string text_;

public:
InsertCommand(TextEditor* editor, const std::string& text)
: editor_(editor), text_(text) {}

void execute() override { editor_->insertText(text_); }
void undo() override { editor_->deleteText(text_.length()); }
std::string getDescription() const override {
return "Insert: '" + text_ + "'";
}
};

// 命令调用者 (支持撤销)
class EditorInvoker {
private:
std::stack<std::shared_ptr<Command>> history_;

public:
void executeCommand(std::shared_ptr<Command> command) {
command->execute();
history_.push(command);
std::cout << "Executed: " << command->getDescription() << std::endl;
}

void undo() {
if (!history_.empty()) {
auto command = history_.top();
history_.pop();
command->undo();
std::cout << "Undid: " << command->getDescription() << std::endl;
}
}
};

// 命令模式 vs 策略模式:
// 命令模式:封装请求,支持撤销、日志、队列
// 策略模式:封装算法,运行时替换行为

各模式对比总结

模式 意图 何时使用 与策略模式区别
策略模式 封装算法家族,使它们可以互换 有多种方式实现同一功能 基准模式
状态模式 对象行为随内部状态改变 对象行为依赖于状态,且状态间有转换 状态自动转换 vs 客户端选择策略
模板方法 定义算法骨架,延迟步骤到子类 算法结构固定,但某些步骤实现变化 继承 vs 组合
命令模式 将请求封装为对象 需要参数化、排队、撤销请求 封装请求 vs 封装算法

常见问题和陷阱

常见问题解答 (FAQ)

Q1: 策略模式会增加太多类吗?

A: 确实会增加类的数量,但这是值得的:

  • 每个策略职责单一,易于理解和测试
  • 可以使用Lambda表达式或std::function减少简单策略的类数量
  • 复杂策略确实需要独立的类来管理
// 简单策略用Lambda
strategies_["simple"] = [](int x) { return x * 2; };

// 复杂策略用独立类
class ComplexStrategy : public Strategy {
// 复杂的状态和逻辑
};

Q2: 什么时候不应该使用策略模式?

A: 在以下情况下避免使用策略模式:

  • 算法很简单,只有2-3个分支
  • 策略之间有复杂的依赖关系
  • 算法变化很少,不需要运行时切换
  • 团队成员不熟悉设计模式
// 简单场景,直接用条件判断更合适
void processOrder(OrderType type, Order& order) {
if (type == OrderType::PREMIUM) {
order.applyDiscount(0.1);
} else {
order.applyDiscount(0.05);
}
}

Q3: 如何选择虚函数还是模板实现?

A: 选择依据:

  • 虚函数:需要运行时多态,策略类型在编译时不确定
  • 模板:追求性能,策略类型在编译时确定,可以内联优化
// 运行时选择 - 使用虚函数
std::unique_ptr<Strategy> createStrategy(const std::string& type) {
if (type == "fast") return std::make_unique<FastStrategy>();
return std::make_unique<DefaultStrategy>();
}

// 编译时确定 - 使用模板
template<typename Strategy>
void processWithStrategy(const Data& data) {
Strategy strategy;
strategy.process(data);
}

常见陷阱和错误

陷阱1: 策略接口设计过于宽泛

// ❌ 不好的设计
class BadStrategy {
public:
virtual void doSomething(void* data) = 0; // 参数类型不明确
virtual int getResult() = 0; // 返回值含义不清
};

// ✅ 好的设计
class GoodStrategy {
public:
virtual CompressionResult compress(const std::vector<uint8_t>& input) = 0;
virtual std::string getName() const = 0;
virtual double getCompressionRatio() const = 0;
};

陷阱2: 忘记处理异常安全

// ❌ 有问题的实现
class UnsafeContext {
Strategy* strategy_;
public:
void setStrategy(Strategy* s) {
delete strategy_; // 如果s构造失败,原策略已删除
strategy_ = s;
}
};

// ✅ 异常安全的实现
class SafeContext {
std::unique_ptr<Strategy> strategy_;
public:
void setStrategy(std::unique_ptr<Strategy> s) {
if (s) { // 先检查新策略有效性
strategy_ = std::move(s);
}
}
};

陷阱3: 内存泄漏风险

// ❌ 容易内存泄漏
class LeakyContext {
Strategy* strategy_;
public:
void setStrategy(Strategy* s) { strategy_ = s; }
// 忘记在析构函数中删除strategy_
};

// ✅ 使用智能指针自动管理
class SafeContext {
std::unique_ptr<Strategy> strategy_;
public:
void setStrategy(std::unique_ptr<Strategy> s) {
strategy_ = std::move(s);
}
// 自动清理,无需手动delete
};

陷阱4: 线程安全问题

// ❌ 线程不安全
class UnsafeContext {
std::shared_ptr<Strategy> strategy_;
public:
void setStrategy(std::shared_ptr<Strategy> s) {
strategy_ = s; // 多线程下可能导致竞态条件
}

void execute() {
strategy_->process(); // strategy_可能在这时被另一线程修改
}
};

// ✅ 线程安全
class ThreadSafeContext {
mutable std::mutex mutex_;
std::shared_ptr<Strategy> strategy_;

public:
void setStrategy(std::shared_ptr<Strategy> s) {
std::lock_guard<std::mutex> lock(mutex_);
strategy_ = s;
}

void execute() {
std::shared_ptr<Strategy> current_strategy;
{
std::lock_guard<std::mutex> lock(mutex_);
current_strategy = strategy_; // 复制策略指针
}
if (current_strategy) {
current_strategy->process(); // 在锁外执行
}
}
};

陷阱5: 过度设计

// ❌ 过度设计 - 为简单逻辑使用策略模式
class OverEngineered {
public:
enum class MathOperation { ADD, SUBTRACT };

void calculate(int a, int b, MathOperation op) {
// 创建复杂的策略系统来处理简单的加减法
auto factory = std::make_unique<MathStrategyFactory>();
auto strategy = factory->createStrategy(op);
return strategy->execute(a, b);
}
};

// ✅ 简单直接
class Simple {
public:
int calculate(int a, int b, MathOperation op) {
switch (op) {
case MathOperation::ADD: return a + b;
case MathOperation::SUBTRACT: return a - b;
}
return 0;
}
};

最佳实践总结

  1. 接口设计:保持接口小而专注,避免上帝接口
  2. 内存管理:使用智能指针,避免手动内存管理
  3. 异常安全:确保策略切换过程中的异常安全
  4. 线程安全:多线程环境下保护策略对象的访问
  5. 性能考虑:频繁调用时考虑使用模板而非虚函数
  6. 适度使用:不要为简单问题过度设计

总结

当然也不要盲目追求设计模式,在行为类型并不多时,直接使用条件判断更加合理。

策略模式对比表

特性 策略模式 条件判断
扩展性 优秀 较差
可读性 良好 一般
性能 虚函数调用开销 条件判断开销
复杂度 较高 较低

选择设计模式时应考虑:

  1. 复杂度:模式是否确实简化了设计?
  2. 可维护性:是否更容易添加新功能?
  3. 性能:是否有不可接受的性能损失?
  4. 团队理解:团队是否熟悉该模式?
CMakeLists Eigen FCPX GNU Gazebo Git Interest IsaacLab KDL Life Linux Matrix ODE PPO QoS ROS Ros UML Ubuntu VcXsrv algorithm algorithms axis-angle bode c++ calibration chrome control cpp dB data_struct dots figure gdb git latex launch life linux mac math matlab memory motor moveit operator optimal algorithm python robot robotics ros ros2 rtb simulation stl thread tools twist urdf valgrind velocity vim web work wsl 强化学习 配置类
知识共享许可协议