设计模式(C++)详解——策略模式(1)
1. 背景与核心概念
1.1 设计模式的起源与发展
策略模式作为经典的23种GoF设计模式之一,诞生于1994年的经典著作《设计模式:可复用面向对象软件的基础》。这本书由四位作者(Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides)共同完成,被业界亲切地称为"四人帮"(Gang of Four)。
发展历程:
- 1994年:GoF首次系统化提出策略模式
- 2000年代:随着C++标准模板库(STL)的普及,函数对象成为实现策略模式的主流方式
- 2011年:C++11引入std::function和lambda表达式,为策略模式提供了更灵活的实现手段
- 至今:策略模式已成为现代C++开发中的基础设计模式
1.2 核心概念解析
策略模式的核心思想:将算法与使用算法的客户端解耦,让算法可以独立于客户端而变化。
关键术语:
- 策略接口(Strategy Interface):定义所有支持算法的公共接口
- 具体策略(Concrete Strategy):实现策略接口的具体算法类
- 上下文(Context):持有一个策略对象的引用,通过策略接口与具体策略交互
1.3 UML类图展示
让我们通过Mermaid UML类图来直观理解策略模式的结构:
2. 设计意图与考量
2.1 核心设计目标
策略模式主要解决以下问题:
- 消除条件语句:避免在代码中使用大量的if-else或switch-case语句
- 开闭原则:对扩展开放,对修改封闭,新增算法无需修改现有代码
- 算法复用:相同的算法可以在不同的环境中重用
2.2 设计权衡因素
优势:
- 符合单一职责原则:每个算法都有自己的类
- 符合开闭原则:无需修改上下文即可引入新策略
- 算法可以自由替换
- 易于单元测试
劣势:
- 客户端必须了解不同策略的区别
- 增加了对象数量
- 策略对象间的通信可能变得复杂
2.3 C++中的特殊实现考量
在C++中,策略模式有几种典型的实现方式:
// 方式1:传统面向对象(基于继承)
class SortStrategy {
public:virtual ~SortStrategy() = default;virtual void sort(std::vector<int>& data) = 0;
};// 方式2:基于函数对象(Functor)
struct QuickSort {void operator()(std::vector<int>& data) const {// 快速排序实现}
};// 方式3:基于std::function(最灵活)
using SortStrategy = std::function<void(std::vector<int>&)>;
3. 实例与应用场景
3.1 案例一:排序算法策略
这是一个经典的策略模式应用场景,展示如何在不同排序算法间动态切换。
完整代码实现
SortStrategy.h
/*** @file SortStrategy.h* @brief 排序策略接口定义*/#ifndef SORT_STRATEGY_H
#define SORT_STRATEGY_H#include <vector>
#include <functional>
#include <memory>/*** @brief 排序策略接口类* * 定义所有排序算法必须实现的接口,使用现代C++的std::function* 提供更大的灵活性,支持函数对象、lambda表达式等*/
class SortStrategy {
public:virtual ~SortStrategy() = default;/*** @brief 执行排序操作* * 对输入的整数向量进行原地排序* * @inout:* - data: 待排序的整数向量,排序后内容会被修改* * @return:* 无返回值,排序结果直接反映在输入参数中*/virtual void sort(std::vector<int>& data) = 0;
};/*** @brief 快速排序策略* * 实现快速排序算法,平均时间复杂度O(n log n)* 使用分治策略,适合大规模数据排序*/
class QuickSortStrategy : public SortStrategy {
public:void sort(std::vector<int>& data) override;private:void quickSort(std::vector<int>& data, int low, int high);int partition(std::vector<int>& data, int low, int high);
};/*** @brief 冒泡排序策略 * * 实现冒泡排序算法,时间复杂度O(n²)* 实现简单,适合小规模数据或教育用途*/
class BubbleSortStrategy : public SortStrategy {
public:void sort(std::vector<int>& data) override;
};/*** @brief 归并排序策略* * 实现归并排序算法,时间复杂度O(n log n)* 稳定排序算法,适合链表排序或外部排序*/
class MergeSortStrategy : public SortStrategy {
public:void sort(std::vector<int>& data) override;private:void mergeSort(std::vector<int>& data, int left, int right);void merge(std::vector<int>& data, int left, int mid, int right);
};/*** @brief 排序上下文类* * 负责维护排序策略的引用,客户端通过此类与策略交互* 支持运行时动态切换排序策略*/
class SorterContext {
public:/*** @brief 设置排序策略* * 在运行时动态设置要使用的排序算法* * @in:* - strategy: 排序策略的unique_ptr,所有权转移给上下文* * @out:* - m_strategy: 更新内部保存的排序策略* * @return:* 无返回值*/void setStrategy(std::unique_ptr<SortStrategy> strategy);/*** @brief 执行排序* * 使用当前设置的策略对数据进行排序* * @inout:* - data: 待排序数据,排序后会被修改* * @return:* 无返回值*/void executeSort(std::vector<int>& data);/*** @brief 获取当前策略名称* * 用于调试和显示当前使用的排序策略* * @return:* 返回当前策略的类型名称字符串*/std::string getStrategyName() const;private:std::unique_ptr<SortStrategy> m_strategy; ///< 当前使用的排序策略
};#endif // SORT_STRATEGY_H
SortStrategy.cpp
/*** @file SortStrategy.cpp* @brief 排序策略具体实现*/#include "SortStrategy.h"
#include <iostream>
#include <algorithm>
#include <string>
#include <typeinfo>// 快速排序策略实现
void QuickSortStrategy::sort(std::vector<int>& data) {if (data.empty()) return;quickSort(data, 0, data.size() - 1);
}void QuickSortStrategy::quickSort(std::vector<int>& data, int low, int high) {if (low < high) {int pivot = partition(data, low, high);quickSort(data, low, pivot - 1);quickSort(data, pivot + 1, high);}
}int QuickSortStrategy::partition(std::vector<int>& data, int low, int high) {int pivot = data[high];int i = low - 1;for (int j = low; j < high; j++) {if (data[j] <= pivot) {i++;std::swap(data[i], data[j]);}}std::swap(data[i + 1], data[high]);return i + 1;
}// 冒泡排序策略实现
void BubbleSortStrategy::sort(std::vector<int>& data) {int n = data.size();for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - i - 1; j++) {if (data[j] > data[j + 1]) {std::swap(data[j], data[j + 1]);}}}
}// 归并排序策略实现
void MergeSortStrategy::sort(std::vector<int>& data) {if (data.empty()) return;mergeSort(data, 0, data.size() - 1);
}void MergeSortStrategy::mergeSort(std::vector<int>& data, int left, int right) {if (left >= right) return;int mid = left + (right - left) / 2;mergeSort(data, left, mid);mergeSort(data, mid + 1, right);merge(data, left, mid, right);
}void MergeSortStrategy::merge(std::vector<int>& data, int left, int mid, int right) {std::vector<int> leftArr(data.begin() + left, data.begin() + mid + 1);std::vector<int> rightArr(data.begin() + mid + 1, data.begin() + right + 1);int i = 0, j = 0, k = left;while (i < leftArr.size() && j < rightArr.size()) {if (leftArr[i] <= rightArr[j]) {data[k] = leftArr[i];i++;} else {data[k] = rightArr[j];j++;}k++;}while (i < leftArr.size()) {data[k] = leftArr[i];i++;k++;}while (j < rightArr.size()) {data[k] = rightArr[j];j++;k++;}
}// 排序上下文实现
void SorterContext::setStrategy(std::unique_ptr<SortStrategy> strategy) {m_strategy = std::move(strategy);
}void SorterContext::executeSort(std::vector<int>& data) {if (m_strategy) {m_strategy->sort(data);} else {std::cerr << "错误:未设置排序策略!" << std::endl;}
}std::string SorterContext::getStrategyName() const {if (!m_strategy) return "无策略";// 使用typeid获取具体类型名称std::string name = typeid(*m_strategy).name();// 清理name(不同编译器返回格式不同)if (name.find("QuickSortStrategy") != std::string::npos) {return "快速排序";} else if (name.find("BubbleSortStrategy") != std::string::npos) {return "冒泡排序";} else if (name.find("MergeSortStrategy") != std::string::npos) {return "归并排序";}return "未知策略";
}
main.cpp
/*** @file main.cpp* @brief 排序策略模式演示程序* * 展示策略模式在排序算法选择中的应用,支持运行时动态切换排序策略*/#include "SortStrategy.h"
#include <iostream>
#include <vector>
#include <random>
#include <memory>/*** @brief 生成随机测试数据* * 生成指定大小的随机整数向量,用于测试排序算法* * @in:* - size: 向量大小* - minVal: 最小值(包含)* - maxVal: 最大值(包含)* * @return:* 返回包含随机整数的vector*/
std::vector<int> generateTestData(int size, int minVal = 1, int maxVal = 1000) {std::vector<int> data;data.reserve(size);std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> dis(minVal, maxVal);for (int i = 0; i < size; i++) {data.push_back(dis(gen));}return data;
}/*** @brief 打印向量内容* * 以可读格式输出向量内容,支持限制输出元素数量* * @in:* - data: 要打印的向量* - maxElements: 最大输出元素数(0表示全部输出)* * @return:* 无返回值*/
void printVector(const std::vector<int>& data, int maxElements = 10) {std::cout << "[";int count = 0;for (int value : data) {if (maxElements > 0 && count >= maxElements) {std::cout << "...";break;}std::cout << value;if (count < static_cast<int>(data.size()) - 1 && (maxElements == 0 || count < maxElements - 1)) {std::cout << ", ";}count++;}std::cout << "]" << std::endl;
}/*** @brief 测试排序策略性能* * 对指定排序策略进行性能测试,测量排序执行时间* * @in:* - context: 排序上下文* - testData: 测试数据* - strategyName: 策略名称(用于输出)* * @return:* 无返回值*/
void testSortPerformance(SorterContext& context, std::vector<int> testData, const std::string& strategyName) {std::cout << "\n=== 测试 " << strategyName << " ===" << std::endl;std::cout << "排序前数据(前10个): ";printVector(testData, 10);auto start = std::chrono::high_resolution_clock::now();context.executeSort(testData);auto end = std::chrono::high_resolution_clock::now();std::cout << "排序后数据(前10个): ";printVector(testData, 10);auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);std::cout << "排序耗时: " << duration.count() << " 微秒" << std::endl;// 验证排序结果bool isSorted = std::is_sorted(testData.begin(), testData.end());std::cout << "排序验证: " << (isSorted ? "✓ 成功" : "✗ 失败") << std::endl;
}int main() {std::cout << "======= 排序策略模式演示 =======" << std::endl;// 生成测试数据const int DATA_SIZE = 1000;auto testData = generateTestData(DATA_SIZE);std::cout << "生成测试数据大小: " << DATA_SIZE << std::endl;SorterContext sorter;// 测试快速排序sorter.setStrategy(std::make_unique<QuickSortStrategy>());testSortPerformance(sorter, testData, sorter.getStrategyName());// 测试冒泡排序sorter.setStrategy(std::make_unique<BubbleSortStrategy>());testSortPerformance(sorter, testData, sorter.getStrategyName());// 测试归并排序sorter.setStrategy(std::make_unique<MergeSortStrategy>());testSortPerformance(sorter, testData, sorter.getStrategyName());std::cout << "\n======= 演示结束 =======" << std::endl;return 0;
}
核心逻辑流程图
Makefile
# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -O2 -g
TARGET := sort_strategy_demo# 源文件和目标文件
SRCS := main.cpp SortStrategy.cpp
OBJS := $(SRCS:.cpp=.o)
HEADERS := SortStrategy.h# 默认目标
$(TARGET): $(OBJS)$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)# 编译规则
%.o: %.cpp $(HEADERS)$(CXX) $(CXXFLAGS) -c $< -o $@# 清理规则
clean:rm -f $(OBJS) $(TARGET)# 安装依赖(如果需要)
install-deps:@echo "确保已安装g++ (版本 >= 7.0) 和 make"# 运行测试
test: $(TARGET)./$(TARGET)# 显示帮助信息
help:@echo "可用目标:"@echo " make 编译程序"@echo " make clean 清理编译结果"@echo " make test 编译并运行程序"@echo " make help 显示此帮助信息".PHONY: clean install-deps test help
操作说明
编译方法:
# 确保系统已安装g++编译器(版本7.0或以上)
make clean && make
运行方式:
./sort_strategy_demo
预期输出:
======= 排序策略模式演示 =======
生成测试数据大小: 1000=== 测试 快速排序 ===
排序前数据(前10个): [542, 123, 876, 234, 765, 432, ...]
排序后数据(前10个): [1, 2, 3, 4, 5, 6, ...]
排序耗时: 1564 微秒
排序验证: ✓ 成功=== 测试 冒泡排序 ===
排序前数据(前10个): [542, 123, 876, 234, 765, 432, ...]
排序后数据(前10个): [1, 2, 3, 4, 5, 6, ...]
排序耗时: 89234 微秒
排序验证: ✓ 成功=== 测试 归并排序 ===
排序前数据(前10个): [542, 123, 876, 234, 765, 432, ...]
排序后数据(前10个): [1, 2, 3, 4, 5, 6, ...]
排序耗时: 1876 微秒
排序验证: ✓ 成功======= 演示结束 =======
结果解读:
- 正常输出:显示三种排序算法的执行时间和排序结果验证
- 性能对比:快速排序和归并排序通常比冒泡排序快很多
- 异常提示:如果未设置策略会显示"错误:未设置排序策略!"
3.2 案例二:支付系统策略
这个案例展示在电商系统中如何灵活切换不同的支付方式。
完整代码实现
PaymentStrategy.h
/*** @file PaymentStrategy.h* @brief 支付策略接口定义*/#ifndef PAYMENT_STRATEGY_H
#define PAYMENT_STRATEGY_H#include <iostream>
#include <memory>
#include <string>/*** @brief 支付请求结构体* * 包含支付所需的所有信息,传递给支付策略执行*/
struct PaymentRequest {std::string orderId; ///< 订单IDdouble amount; ///< 支付金额std::string currency; ///< 货币类型std::string customerId; ///< 客户IDPaymentRequest(const std::string& order, double amt, const std::string& curr = "CNY", const std::string& customer = ""): orderId(order), amount(amt), currency(curr), customerId(customer) {}
};/*** @brief 支付结果结构体* * 包含支付执行的结果信息*/
struct PaymentResult {bool success; ///< 支付是否成功std::string transactionId; ///< 交易IDstd::string message; ///< 结果消息PaymentResult(bool succ = false, const std::string& transId = "", const std::string& msg = ""): success(succ), transactionId(transId), message(msg) {}
};/*** @brief 支付策略接口* * 定义所有支付方式必须实现的接口*/
class PaymentStrategy {
public:virtual ~PaymentStrategy() = default;/*** @brief 执行支付* * 根据支付请求执行具体的支付操作* * @in:* - request: 支付请求信息* * @return:* 返回支付结果,包含成功状态和交易信息*/virtual PaymentResult pay(const PaymentRequest& request) = 0;/*** @brief 获取支付方式名称* * @return:* 返回支付方式的显示名称*/virtual std::string getName() const = 0;
};/*** @brief 支付宝支付策略*/
class AlipayStrategy : public PaymentStrategy {
public:PaymentResult pay(const PaymentRequest& request) override;std::string getName() const override { return "支付宝"; }
};/*** @brief 微信支付策略*/
class WechatPayStrategy : public PaymentStrategy {
public:PaymentResult pay(const PaymentRequest& request) override;std::string getName() const override { return "微信支付"; }
};/*** @brief 信用卡支付策略*/
class CreditCardStrategy : public PaymentStrategy {
public:PaymentResult pay(const PaymentRequest& request) override;std::string getName() const override { return "信用卡"; }private:std::string simulateBankProcessing(const PaymentRequest& request);
};/*** @brief 支付上下文类* * 管理支付策略,提供统一的支付接口*/
class PaymentContext {
public:/*** @brief 设置支付策略*/void setStrategy(std::unique_ptr<PaymentStrategy> strategy);/*** @brief 执行支付操作* * @in:* - request: 支付请求* * @return:* 返回支付结果*/PaymentResult executePayment(const PaymentRequest& request);/*** @brief 获取当前支付方式名称*/std::string getCurrentMethod() const;private:std::unique_ptr<PaymentStrategy> m_strategy;
};#endif // PAYMENT_STRATEGY_H
PaymentStrategy.cpp
/*** @file PaymentStrategy.cpp* @brief 支付策略具体实现*/#include "PaymentStrategy.h"
#include <random>
#include <sstream>// 支付宝支付实现
PaymentResult AlipayStrategy::pay(const PaymentRequest& request) {std::cout << "🔵 支付宝支付处理中..." << std::endl;std::cout << " 订单: " << request.orderId << std::endl;std::cout << " 金额: " << request.amount << " " << request.currency << std::endl;// 模拟支付处理std::this_thread::sleep_for(std::chrono::milliseconds(500));// 生成模拟交易IDstd::stringstream ss;ss << "ALIPAY_" << request.orderId << "_" << std::time(nullptr);// 模拟90%的成功率std::random_device rd;std::mt19937 gen(rd());std::uniform_real_distribution<double> dis(0.0, 1.0);bool success = dis(gen) > 0.1; // 90%成功率if (success) {return PaymentResult(true, ss.str(), "支付宝支付成功");} else {return PaymentResult(false, "", "支付宝支付失败:余额不足");}
}// 微信支付实现
PaymentResult WechatPayStrategy::pay(const PaymentRequest& request) {std::cout << "🟢 微信支付处理中..." << std::endl;std::cout << " 订单: " << request.orderId << std::endl;std::cout << " 金额: " << request.amount << " " << request.currency << std::endl;// 模拟支付处理std::this_thread::sleep_for(std::chrono::milliseconds(400));// 生成模拟交易IDstd::stringstream ss;ss << "WECHAT_" << request.orderId << "_" << std::time(nullptr);// 模拟95%的成功率std::random_device rd;std::mt19937 gen(rd());std::uniform_real_distribution<double> dis(0.0, 1.0);bool success = dis(gen) > 0.05; // 95%成功率if (success) {return PaymentResult(true, ss.str(), "微信支付成功");} else {return PaymentResult(false, "", "微信支付失败:网络异常");}
}// 信用卡支付实现
PaymentResult CreditCardStrategy::pay(const PaymentRequest& request) {std::cout << "🟣 信用卡支付处理中..." << std::endl;std::cout << " 订单: " << request.orderId << std::endl;std::cout << " 金额: " << request.amount << " " << request.currency << std::endl;// 模拟银行处理std::string bankResponse = simulateBankProcessing(request);if (bankResponse == "APPROVED") {std::stringstream ss;ss << "CC_" << request.orderId << "_" << std::time(nullptr);return PaymentResult(true, ss.str(), "信用卡支付成功");} else {return PaymentResult(false, "", "信用卡支付失败:" + bankResponse);}
}std::string CreditCardStrategy::simulateBankProcessing(const PaymentRequest& request) {std::this_thread::sleep_for(std::chrono::milliseconds(800));std::random_device rd;std::mt19937 gen(rd());std::uniform_real_distribution<double> dis(0.0, 1.0);double randomValue = dis(gen);if (randomValue > 0.15) { // 85%批准率return "APPROVED";} else if (randomValue > 0.05) { // 10%拒绝率return "DECLINED";} else { // 5%系统错误return "SYSTEM_ERROR";}
}// 支付上下文实现
void PaymentContext::setStrategy(std::unique_ptr<PaymentStrategy> strategy) {m_strategy = std::move(strategy);
}PaymentResult PaymentContext::executePayment(const PaymentRequest& request) {if (!m_strategy) {return PaymentResult(false, "", "未设置支付策略");}std::cout << "\n💳 开始支付流程..." << std::endl;std::cout << "支付方式: " << m_strategy->getName() << std::endl;auto result = m_strategy->pay(request);std::cout << "支付结果: " << (result.success ? "✅ 成功" : "❌ 失败") << std::endl;if (!result.message.empty()) {std::cout << "结果信息: " << result.message << std::endl;}if (result.success && !result.transactionId.empty()) {std::cout << "交易ID: " << result.transactionId << std::endl;}return result;
}std::string PaymentContext::getCurrentMethod() const {return m_strategy ? m_strategy->getName() : "未设置";
}
payment_demo.cpp
/*** @file payment_demo.cpp* @brief 支付策略演示程序*/#include "PaymentStrategy.h"
#include <iostream>
#include <memory>
#include <vector>/*** @brief 模拟电商支付流程*/
void simulateEcommercePayment() {std::cout << "🛒 === 电商支付系统演示 ===" << std::endl;PaymentContext paymentContext;PaymentRequest request("ORDER_2024_001", 299.99, "CNY", "CUST_1001");// 测试支付宝支付std::cout << "\n📱 场景1: 客户选择支付宝支付" << std::endl;paymentContext.setStrategy(std::make_unique<AlipayStrategy>());paymentContext.executePayment(request);// 测试微信支付std::cout << "\n📱 场景2: 客户选择微信支付" << std::endl;paymentContext.setStrategy(std::make_unique<WechatPayStrategy>());paymentContext.executePayment(request);// 测试信用卡支付std::cout << "\n💳 场景3: 客户选择信用卡支付" << std::endl;paymentContext.setStrategy(std::make_unique<CreditCardStrategy>());paymentContext.executePayment(request);
}/*** @brief 模拟支付策略动态切换*/
void demonstrateDynamicSwitching() {std::cout << "\n🔄 === 动态策略切换演示 ===" << std::endl;PaymentContext context;std::vector<PaymentRequest> orders = {{"ORDER_2024_002", 150.50, "CNY", "CUST_1002"},{"ORDER_2024_003", 89.99, "CNY", "CUST_1003"},{"ORDER_2024_004", 450.00, "CNY", "CUST_1004"}};std::vector<std::unique_ptr<PaymentStrategy>> strategies;strategies.push_back(std::make_unique<AlipayStrategy>());strategies.push_back(std::make_unique<WechatPayStrategy>());strategies.push_back(std::make_unique<CreditCardStrategy>());for (size_t i = 0; i < orders.size(); ++i) {std::cout << "\n--- 处理订单 " << (i + 1) << " ---" << std::endl;context.setStrategy(std::move(strategies[i]));context.executePayment(orders[i]);// 重新创建策略对象以便下次使用if (i == 0) strategies[i] = std::make_unique<AlipayStrategy>();else if (i == 1) strategies[i] = std::make_unique<WechatPayStrategy>();else strategies[i] = std::make_unique<CreditCardStrategy>();}
}/*** @brief 统计支付成功率*/
void analyzePaymentSuccessRate() {std::cout << "\n📊 === 支付成功率分析 ===" << std::endl;const int TEST_COUNT = 100;std::vector<std::unique_ptr<PaymentStrategy>> strategies;strategies.push_back(std::make_unique<AlipayStrategy>());strategies.push_back(std::make_unique<WechatPayStrategy>());strategies.push_back(std::make_unique<CreditCardStrategy>());std::vector<std::string> strategyNames = {"支付宝", "微信支付", "信用卡"};PaymentRequest testRequest("TEST_ORDER", 100.0);for (size_t i = 0; i < strategies.size(); ++i) {int successCount = 0;std::cout << "\n测试 " << strategyNames[i] << " (" << TEST_COUNT << "次):" << std::endl;for (int j = 0; j < TEST_COUNT; ++j) {auto result = strategies[i]->pay(testRequest);if (result.success) {successCount++;}}double successRate = (static_cast<double>(successCount) / TEST_COUNT) * 100;std::cout << "成功次数: " << successCount << "/" << TEST_COUNT << std::endl;std::cout << "成功率: " << successRate << "%" << std::endl;}
}int main() {std::cout << "💰 支付策略模式演示程序" << std::endl;std::cout << "=======================" << std::endl;simulateEcommercePayment();demonstrateDynamicSwitching();analyzePaymentSuccessRate();std::cout << "\n🎉 演示程序结束" << std::endl;return 0;
}
支付流程时序图
Makefile补充
在之前的Makefile基础上添加支付演示目标:
# 支付演示程序
PAYMENT_TARGET := payment_demo
PAYMENT_SRCS := payment_demo.cpp PaymentStrategy.cpp
PAYMENT_OBJS := $(PAYMENT_SRCS:.cpp=.o)$(PAYMENT_TARGET): $(PAYMENT_OBJS)$(CXX) $(CXXFLAGS) -o $(PAYMENT_TARGET) $(PAYMENT_OBJS) -lpthreadpayment_demo.o: payment_demo.cpp PaymentStrategy.h$(CXX) $(CXXFLAGS) -c payment_demo.cpp -o payment_demo.oPaymentStrategy.o: PaymentStrategy.cpp PaymentStrategy.h$(CXX) $(CXXFLAGS) -c PaymentStrategy.cpp -o PaymentStrategy.o# 更新clean规则
clean:rm -f $(OBJS) $(TARGET) $(PAYMENT_OBJS) $(PAYMENT_TARGET)# 支付测试
test-payment: $(PAYMENT_TARGET)./$(PAYMENT_TARGET)
操作说明
编译方法:
make clean && make payment_demo
运行方式:
./payment_demo
预期输出:
💰 支付策略模式演示程序
=======================🛒 === 电商支付系统演示 ===📱 场景1: 客户选择支付宝支付💳 开始支付流程...
支付方式: 支付宝
🔵 支付宝支付处理中...订单: ORDER_2024_001金额: 299.99 CNY
支付结果: ✅ 成功
结果信息: 支付宝支付成功
交易ID: ALIPAY_ORDER_2024_001_1700000000🔄 === 动态策略切换演示 ===--- 处理订单 1 ---
💳 开始支付流程...
支付方式: 支付宝
🔵 支付宝支付处理中...
...📊 === 支付成功率分析 ===测试 支付宝 (100次):
成功次数: 89/100
成功率: 89%🎉 演示程序结束
3.3 案例三:游戏角色攻击策略
这个案例展示在游戏开发中如何使用策略模式实现不同的攻击行为。
完整代码实现
AttackStrategy.h
/*** @file AttackStrategy.h * @brief 游戏角色攻击策略接口*/#ifndef ATTACK_STRATEGY_H
#define ATTACK_STRATEGY_H#include <iostream>
#include <memory>
#include <string>
#include <random>/*** @brief 游戏角色类*/
class GameCharacter {
public:GameCharacter(const std::string& name, int health = 100) : m_name(name), m_health(health) {}std::string getName() const { return m_name; }int getHealth() const { return m_health; }void setHealth(int health) { m_health = health; }void takeDamage(int damage) { m_health -= damage; }private:std::string m_name;int m_health;
};/*** @brief 攻击策略接口*/
class AttackStrategy {
public:virtual ~AttackStrategy() = default;/*** @brief 执行攻击* * @in:* - attacker: 攻击者角色* - target: 目标角色* * @return:* 返回造成的伤害值*/virtual int executeAttack(GameCharacter& attacker, GameCharacter& target) = 0;/*** @brief 获取策略名称*/virtual std::string getName() const = 0;/*** @brief 获取策略描述*/virtual std::string getDescription() const = 0;
};/*** @brief 近战攻击策略*/
class MeleeAttack : public AttackStrategy {
public:int executeAttack(GameCharacter& attacker, GameCharacter& target) override;std::string getName() const override { return "近战攻击"; }std::string getDescription() const override { return "使用剑或斧头进行近距离物理攻击"; }
};/*** @brief 远程攻击策略 */
class RangedAttack : public AttackStrategy {
public:int executeAttack(GameCharacter& attacker, GameCharacter& target) override;std::string getName() const override { return "远程攻击"; }std::string getDescription() const override { return "使用弓箭或枪械进行远距离攻击"; }
};/*** @brief 魔法攻击策略*/
class MagicAttack : public AttackStrategy {
public:int executeAttack(GameCharacter& attacker, GameCharacter& target) override;std::string getName() const override { return "魔法攻击"; }std::string getDescription() const override { return "使用魔法咒语进行元素攻击"; }
};/*** @brief 偷袭策略*/
class SneakAttack : public AttackStrategy {
public:int executeAttack(GameCharacter& attacker, GameCharacter& target) override;std::string getName() const override { return "偷袭"; }std::string getDescription() const override { return "从背后发动致命一击,有几率造成暴击"; }
};/*** @brief 角色战斗上下文*/
class BattleContext {
public:BattleContext(const std::string& characterName);void setAttackStrategy(std::unique_ptr<AttackStrategy> strategy);void attack(GameCharacter& target);void displayStatus() const;std::string getCurrentStrategy() const;private:GameCharacter m_character;std::unique_ptr<AttackStrategy> m_attackStrategy;
};#endif // ATTACK_STRATEGY_H
AttackStrategy.cpp
/*** @file AttackStrategy.cpp* @brief 攻击策略具体实现*/#include "AttackStrategy.h"
#include <random>// 近战攻击实现
int MeleeAttack::executeAttack(GameCharacter& attacker, GameCharacter& target) {std::cout << "⚔️ " << attacker.getName() << " 发动近战攻击!" << std::endl;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> damageDis(15, 25);std::uniform_real_distribution<double> hitDis(0.0, 1.0);int damage = damageDis(gen);double hitChance = hitDis(gen);if (hitChance < 0.1) { // 10%几率missstd::cout << " 💨 攻击未命中!" << std::endl;return 0;} else if (hitChance > 0.9) { // 10%几率暴击damage *= 2;std::cout << " 💥 暴击!造成 " << damage << " 点伤害!" << std::endl;} else {std::cout << " ✅ 命中!造成 " << damage << " 点伤害" << std::endl;}target.takeDamage(damage);return damage;
}// 远程攻击实现
int RangedAttack::executeAttack(GameCharacter& attacker, GameCharacter& target) {std::cout << "🏹 " << attacker.getName() << " 发动远程攻击!" << std::endl;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> damageDis(10, 20);std::uniform_real_distribution<double> hitDis(0.0, 1.0);int damage = damageDis(gen);double hitChance = hitDis(gen);if (hitChance < 0.2) { // 20%几率miss(远程更容易miss)std::cout << " 💨 箭矢偏离目标!" << std::endl;return 0;} else {std::cout << " ✅ 精准命中!造成 " << damage << " 点伤害" << std::endl;}target.takeDamage(damage);return damage;
}// 魔法攻击实现
int MagicAttack::executeAttack(GameCharacter& attacker, GameCharacter& target) {std::cout << "🔮 " << attacker.getName() << " 吟唱魔法咒语!" << std::endl;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> damageDis(20, 35);std::uniform_real_distribution<double> hitDis(0.0, 1.0);int damage = damageDis(gen);double hitChance = hitDis(gen);if (hitChance < 0.05) { // 5%几率失败std::cout << " 💫 魔法施放失败!" << std::endl;return 0;} else if (hitChance > 0.85) { // 15%几率元素爆发damage *= 1.5;std::cout << " 🌟 元素爆发!造成 " << damage << " 点魔法伤害!" << std::endl;} else {std::cout << " ✨ 魔法命中!造成 " << damage << " 点伤害" << std::endl;}target.takeDamage(damage);return damage;
}// 偷袭实现
int SneakAttack::executeAttack(GameCharacter& attacker, GameCharacter& target) {std::cout << "🗡️ " << attacker.getName() << " 悄悄接近目标..." << std::endl;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> damageDis(5, 15);std::uniform_real_distribution<double> critDis(0.0, 1.0);int damage = damageDis(gen);double critChance = critDis(gen);if (critChance > 0.7) { // 30%几率致命一击damage *= 3;std::cout << " 💀 致命一击!造成 " << damage << " 点巨大伤害!" << std::endl;} else if (critChance < 0.1) { // 10%几率被发现std::cout << " 👀 被目标发现!偷袭失败" << std::endl;return 0;} else {std::cout << " 🎯 偷袭成功!造成 " << damage << " 点伤害" << std::endl;}target.takeDamage(damage);return damage;
}// 战斗上下文实现
BattleContext::BattleContext(const std::string& characterName) : m_character(characterName) {}void BattleContext::setAttackStrategy(std::unique_ptr<AttackStrategy> strategy) {m_attackStrategy = std::move(strategy);
}void BattleContext::attack(GameCharacter& target) {if (!m_attackStrategy) {std::cout << "❌ " << m_character.getName() << " 没有设置攻击策略!" << std::endl;return;}std::cout << "\n🎯 " << m_character.getName() << " 对 " << target.getName() << " 发动攻击" << std::endl;std::cout << "攻击方式: " << m_attackStrategy->getName() << std::endl;std::cout << "描述: " << m_attackStrategy->getDescription() << std::endl;m_attackStrategy->executeAttack(m_character, target);
}void BattleContext::displayStatus() const {std::cout << "👤 " << m_character.getName() << " | 生命值: " << m_character.getHealth()<< " | 攻击策略: " << getCurrentStrategy() << std::endl;
}std::string BattleContext::getCurrentStrategy() const {return m_attackStrategy ? m_attackStrategy->getName() : "无";
}
game_demo.cpp
/*** @file game_demo.cpp * @brief 游戏攻击策略演示*/#include "AttackStrategy.h"
#include <iostream>
#include <memory>
#include <vector>/*** @brief 模拟角色战斗*/
void simulateBattle() {std::cout << "⚔️ === 游戏战斗模拟 ===" << std::endl;// 创建角色BattleContext warrior("战士亚瑟");BattleContext mage("法师梅林"); BattleContext archer("弓箭手罗宾");BattleContext rogue("盗贼艾吉奥");GameCharacter dragon("邪恶巨龙", 200);std::cout << "\n🐉 出现强敌: " << dragon.getName() << " (生命值: " << dragon.getHealth() << ")" << std::endl;// 设置各角色攻击策略warrior.setAttackStrategy(std::make_unique<MeleeAttack>());mage.setAttackStrategy(std::make_unique<MagicAttack>());archer.setAttackStrategy(std::make_unique<RangedAttack>());rogue.setAttackStrategy(std::make_unique<SneakAttack>());// 显示角色状态std::cout << "\n🎮 队伍状态:" << std::endl;warrior.displayStatus();mage.displayStatus(); archer.displayStatus();rogue.displayStatus();// 战斗回合std::cout << "\n🔥 战斗开始!" << std::endl;int round = 1;while (dragon.getHealth() > 0) {std::cout << "\n--- 第 " << round << " 回合 ---" << std::endl;warrior.attack(dragon);if (dragon.getHealth() <= 0) break;mage.attack(dragon);if (dragon.getHealth() <= 0) break;archer.attack(dragon);if (dragon.getHealth() <= 0) break;rogue.attack(dragon);if (dragon.getHealth() <= 0) break;std::cout << "🐉 巨龙剩余生命值: " << dragon.getHealth() << std::endl;round++;if (round > 10) {std::cout << "⏰ 战斗超时!" << std::endl;break;}}std::cout << "\n🎉 战斗结束!" << std::endl;if (dragon.getHealth() <= 0) {std::cout << "✅ 队伍击败了 " << dragon.getName() << "!" << std::endl;} else {std::cout << "❌ 队伍未能击败 " << dragon.getName() << std::endl;}
}/*** @brief 演示策略动态切换*/
void demonstrateStrategySwitching() {std::cout << "\n🔄 === 策略动态切换演示 ===" << std::endl;BattleContext hero("全能英雄");GameCharacter goblin("哥布林", 50);std::vector<std::unique_ptr<AttackStrategy>> strategies;strategies.push_back(std::make_unique<MeleeAttack>());strategies.push_back(std::make_unique<RangedAttack>());strategies.push_back(std::make_unique<MagicAttack>());strategies.push_back(std::make_unique<SneakAttack>());std::cout << "🎯 英雄将尝试所有攻击方式:" << std::endl;for (auto& strategy : strategies) {hero.setAttackStrategy(std::move(strategy));hero.attack(goblin);std::cout << "哥布林剩余生命值: " << goblin.getHealth() << std::endl;// 重置哥布林生命值goblin = GameCharacter("哥布林", 50);// 重新创建策略对象if (strategy == nullptr) {if (strategies[0] == nullptr) strategy = std::make_unique<MeleeAttack>();else if (strategies[1] == nullptr) strategy = std::make_unique<RangedAttack>();else if (strategies[2] == nullptr) strategy = std::make_unique<MagicAttack>();else strategy = std::make_unique<SneakAttack>();}}
}/*** @brief 分析不同策略的伤害输出*/
void analyzeDamageOutput() {std::cout << "\n📊 === 攻击策略伤害分析 ===" << std::endl;const int TEST_COUNT = 1000;GameCharacter dummy("训练假人", 10000);GameCharacter attacker("测试角色");std::vector<std::unique_ptr<AttackStrategy>> strategies;strategies.push_back(std::make_unique<MeleeAttack>());strategies.push_back(std::make_unique<RangedAttack>());strategies.push_back(std::make_unique<MagicAttack>());strategies.push_back(std::make_unique<SneakAttack>());std::vector<std::string> strategyNames = {"近战攻击", "远程攻击", "魔法攻击", "偷袭"};for (size_t i = 0; i < strategies.size(); ++i) {int totalDamage = 0;int hitCount = 0;int critCount = 0;std::cout << "\n分析 " << strategyNames[i] << " (" << TEST_COUNT << "次攻击):" << std::endl;for (int j = 0; j < TEST_COUNT; ++j) {int damage = strategies[i]->executeAttack(attacker, dummy);if (damage > 0) {totalDamage += damage;hitCount++;}}double avgDamage = static_cast<double>(totalDamage) / TEST_COUNT;double hitRate = (static_cast<double>(hitCount) / TEST_COUNT) * 100;std::cout << "总伤害: " << totalDamage << std::endl;std::cout << "平均每次攻击伤害: " << avgDamage << std::endl;std::cout << "命中率: " << hitRate << "%" << std::endl;}
}int main() {std::cout << "🎮 游戏攻击策略模式演示" << std::endl;std::cout << "========================" << std::endl;simulateBattle();demonstrateStrategySwitching();analyzeDamageOutput();std::cout << "\n🏁 演示程序结束" << std::endl;return 0;
}
战斗系统类图
Makefile完整版
# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -O2 -g
LDFLAGS := -lpthread# 目标程序
TARGETS := sort_strategy_demo payment_demo game_demo# 排序演示
SORT_SRCS := main.cpp SortStrategy.cpp
SORT_OBJS := $(SORT_SRCS:.cpp=.o)# 支付演示
PAYMENT_SRCS := payment_demo.cpp PaymentStrategy.cpp
PAYMENT_OBJS := $(PAYMENT_SRCS:.cpp=.o)# 游戏演示
GAME_SRCS := game_demo.cpp AttackStrategy.cpp
GAME_OBJS := $(GAME_SRCS:.cpp=.o)# 头文件
HEADERS := SortStrategy.h PaymentStrategy.h AttackStrategy.h# 默认编译所有目标
all: $(TARGETS)# 排序演示目标
sort_strategy_demo: $(SORT_OBJS)$(CXX) $(CXXFLAGS) -o $@ $(SORT_OBJS)# 支付演示目标
payment_demo: $(PAYMENT_OBJS)$(CXX) $(CXXFLAGS) -o $@ $(PAYMENT_OBJS) $(LDFLAGS)# 游戏演示目标
game_demo: $(GAME_OBJS)$(CXX) $(CXXFLAGS) -o $@ $(GAME_OBJS)# 通用编译规则
%.o: %.cpp $(HEADERS)$(CXX) $(CXXFLAGS) -c $< -o $@# 清理规则
clean:rm -f *.o $(TARGETS)# 安装依赖检查
check-deps:@echo "检查编译依赖..."@which $(CXX) > /dev/null && echo "✅ g++ 编译器: 已安装" || echo "❌ g++ 编译器: 未安装"@echo "C++ 标准: C++17"@echo "所需头文件: <iostream>, <vector>, <memory>, <functional>, <random>, <chrono>, <thread>"# 测试所有演示
test-all: all@echo "测试排序演示..."@./sort_strategy_demo > /dev/null && echo "✅ 排序演示: 通过" || echo "❌ 排序演示: 失败"@echo "测试支付演示..."@./payment_demo > /dev/null && echo "✅ 支付演示: 通过" || echo "❌ 支付演示: 失败" @echo "测试游戏演示..."@./game_demo > /dev/null && echo "✅ 游戏演示: 通过" || echo "❌ 游戏演示: 失败"# 显示帮助信息
help:@echo "可用目标:"@echo " make all 编译所有演示程序"@echo " make clean 清理所有编译结果"@echo " make check-deps 检查编译依赖"@echo " make test-all 编译并测试所有演示"@echo " make help 显示此帮助信息"@echo ""@echo "单独编译:"@echo " make sort_strategy_demo"@echo " make payment_demo" @echo " make game_demo".PHONY: all clean check-deps test-all help
4. 策略模式的高级应用与最佳实践
4.1 使用std::function的现代C++实现
除了传统的面向对象实现,现代C++更推荐使用std::function:
/*** @brief 使用std::function的策略模式示例*/
class ModernSorter {
public:using SortAlgorithm = std::function<void(std::vector<int>&)>;void setStrategy(SortAlgorithm algorithm) {m_algorithm = std::move(algorithm);}void sort(std::vector<int>& data) {if (m_algorithm) {m_algorithm(data);}}private:SortAlgorithm m_algorithm;
};// 使用lambda表达式作为策略
auto quickSort = [](std::vector<int>& data) {std::sort(data.begin(), data.end());
};auto reverseSort = [](std::vector<int>& data) {std::sort(data.rbegin(), data.rend());
};// 使用示例
ModernSorter sorter;
sorter.setStrategy(quickSort);
sorter.setStrategy([](std::vector<int>& data) {// 自定义排序逻辑std::sort(data.begin(), data.end(), std::greater<int>());
});
4.2 策略工厂模式结合
在实际项目中,策略模式常与工厂模式结合使用:
/*** @brief 策略工厂类*/
class StrategyFactory {
public:static std::unique_ptr<PaymentStrategy> createPaymentStrategy(const std::string& type) {if (type == "alipay") {return std::make_unique<AlipayStrategy>();} else if (type == "wechat") {return std::make_unique<WechatPayStrategy>();} else if (type == "creditcard") {return std::make_unique<CreditCardStrategy>();}return nullptr;}static std::unique_ptr<AttackStrategy> createAttackStrategy(const std::string& type) {// 类似的工厂方法...return nullptr;}
};
4.3 性能考量与优化
性能优化建议:
- 对于简单的策略,使用函数指针或std::function可能比虚函数调用更快
- 考虑使用模板策略在编译期确定算法
- 对于性能敏感的场景,避免频繁的策略切换
/*** @brief 模板策略模式(编译期多态)*/
template<typename Strategy>
class TemplateContext {
public:void execute(const std::vector<int>& data) {Strategy strategy;strategy.process(data);}
};
5. 总结
策略模式是C++开发中极其重要的设计模式,它通过将算法封装成独立的策略类,实现了算法的自由切换和扩展。通过本文的三个完整案例,我们展示了策略模式在不同场景下的应用:
- 排序算法:展示了算法策略的动态切换
- 支付系统:演示了业务逻辑策略的灵活配置
- 游戏战斗:体现了行为策略的多样性
核心价值:
- ✅ 符合开闭原则,易于扩展
- ✅ 消除复杂的条件判断
- ✅ 提高代码的可测试性
- ✅ 促进代码复用
适用场景:
- 一个系统需要在多种算法中选择一种
- 需要避免暴露复杂的、与算法相关的数据结构
- 一个类定义了多种行为,这些行为以多个条件语句的形式出现
策略模式与现代C++特性(如std::function、lambda表达式)结合,能够写出更加灵活、可维护的代码,是每个C++开发者必须掌握的重要设计模式。