C++策略模式:灵活算法的优雅实现
策略模式的核心思想
策略模式属于行为型设计模式,通过定义一系列算法并将其封装成独立的类,使它们可以相互替换。该模式让算法的变化独立于使用它的客户端,提升系统的灵活性和可扩展性。
在C++中,策略模式通常通过抽象基类定义算法接口,具体策略类实现该接口,上下文类持有策略对象的引用并通过接口调用算法。
策略模式的实现结构
抽象策略类
定义所有支持的算法或行为的公共接口,通常为纯虚基类:
class Strategy {
public:
virtual void execute() const = 0;
virtual ~Strategy() = default;
};
具体策略类
实现抽象策略定义的接口,提供具体算法实现:
class ConcreteStrategyA : public Strategy {
public:
void execute() const override {
std::cout << "Executing Strategy A\n";
}
};
class ConcreteStrategyB : public Strategy {
public:
void execute() const override {
std::cout << "Executing Strategy B\n";
}
};
上下文类
维护策略对象的引用,通过策略接口与具体策略交互:
class Context {
private:
std::unique_ptr<Strategy> strategy;
public:
explicit Context(std::unique_ptr<Strategy>&& s) : strategy(std::move(s)) {}
void setStrategy(std::unique_ptr<Strategy>&& s) {
strategy = std::move(s);
}
void executeStrategy() const {
strategy->execute();
}
};
策略模式的应用示例
以下示例展示支付系统中不同支付策略的动态切换:
// 支付策略接口
class PaymentStrategy {
public:
virtual void pay(double amount) const = 0;
virtual ~PaymentStrategy() = default;
};
// 具体支付策略
class CreditCardPayment : public PaymentStrategy {
public:
void pay(double amount) const override {
std::cout << "Paying $" << amount << " via Credit Card\n";
}
};
class PayPalPayment : public PaymentStrategy {
public:
void pay(double amount) const override {
std::cout << "Paying $" << amount << " via PayPal\n";
}
};
// 支付上下文
class PaymentProcessor {
std::unique_ptr<PaymentStrategy> strategy;
public:
void setStrategy(std::unique_ptr<PaymentStrategy>&& s) {
strategy = std::move(s);
}
void processPayment(double amount) const {
strategy->pay(amount);
}
};
// 客户端代码
int main() {
PaymentProcessor processor;
processor.setStrategy(std::make_unique<CreditCardPayment>());
processor.processPayment(100.0);
processor.setStrategy(std::make_unique<PayPalPayment>());
processor.processPayment(200.0);
}
策略模式的优缺点分析
优点
- 符合开闭原则:新增策略无需修改现有代码
- 消除条件语句:避免使用大量if-else或switch-case判断不同策略
- 提高复用性:相同策略可被不同上下文复用
缺点
- 客户端必须了解所有策略:需要知道不同策略的区别以选择合适的策略
- 增加对象数量:每个具体策略都会产生一个新类
- 通信开销:策略与上下文可能需要通过接口传递额外数据
策略模式与状态模式的区别
虽然两者结构相似,但存在本质差异:
- 策略模式:客户端主动选择策略,策略之间通常独立且无状态转换
- 状态模式:状态转换由内部条件触发,状态之间可能存在关联关系
现代C++实现的改进
使用std::function和lambda表达式可以简化策略模式的实现:
class ModernContext {
private:
std::function<void()> strategy;
public:
void setStrategy(std::function<void()>&& s) {
strategy = std::move(s);
}
void execute() const {
strategy();
}
};
// 客户端代码
ModernContext ctx;
ctx.setStrategy([](){ std::cout << "Lambda Strategy\n"; });
ctx.execute();
实际应用场景
- 排序算法选择:根据数据特征选择快速排序、归并排序等不同策略
- 压缩算法切换:支持ZIP、RAR等多种压缩格式
- 游戏AI行为:NPC根据环境选择攻击、逃跑或巡逻等不同行为策略
- 验证系统:支持密码验证、指纹验证、面部识别等多种验证方式
性能考量
在性能敏感场景中需注意:
- 虚函数调用开销:策略模式涉及动态绑定,可能影响性能
- 对象创建成本:频繁切换策略可能导致对象反复创建销毁
- 内存占用:大量策略类会增加内存消耗
可通过对象池、策略缓存等技术进行优化。
BbS.okacop071.info/PoSt/1120_250675.HtM
BbS.okacop072.info/PoSt/1120_842276.HtM
BbS.okacop073.info/PoSt/1120_930727.HtM
BbS.okacop074.info/PoSt/1120_023962.HtM
BbS.okacop075.info/PoSt/1120_326080.HtM
BbS.okacop076.info/PoSt/1120_246601.HtM
BbS.okacop077.info/PoSt/1120_003959.HtM
BbS.okacop078.info/PoSt/1120_204792.HtM
BbS.okacop079.info/PoSt/1120_655035.HtM
BbS.okacop080.info/PoSt/1120_667548.HtM
BbS.okacop071.info/PoSt/1120_672229.HtM
BbS.okacop072.info/PoSt/1120_922789.HtM
BbS.okacop073.info/PoSt/1120_251581.HtM
BbS.okacop074.info/PoSt/1120_725288.HtM
BbS.okacop075.info/PoSt/1120_377538.HtM
BbS.okacop076.info/PoSt/1120_993887.HtM
BbS.okacop077.info/PoSt/1120_690307.HtM
BbS.okacop078.info/PoSt/1120_984111.HtM
BbS.okacop079.info/PoSt/1120_526499.HtM
BbS.okacop080.info/PoSt/1120_019894.HtM
BbS.okacop071.info/PoSt/1120_800303.HtM
BbS.okacop072.info/PoSt/1120_836642.HtM
BbS.okacop073.info/PoSt/1120_334887.HtM
BbS.okacop074.info/PoSt/1120_608689.HtM
BbS.okacop075.info/PoSt/1120_891100.HtM
BbS.okacop076.info/PoSt/1120_627740.HtM
BbS.okacop077.info/PoSt/1120_330379.HtM
BbS.okacop078.info/PoSt/1120_100449.HtM
BbS.okacop079.info/PoSt/1120_707866.HtM
BbS.okacop080.info/PoSt/1120_741987.HtM
BbS.okacop071.info/PoSt/1120_886880.HtM
BbS.okacop072.info/PoSt/1120_729695.HtM
BbS.okacop073.info/PoSt/1120_703122.HtM
BbS.okacop074.info/PoSt/1120_695357.HtM
BbS.okacop075.info/PoSt/1120_737369.HtM
BbS.okacop076.info/PoSt/1120_809924.HtM
BbS.okacop077.info/PoSt/1120_993587.HtM
BbS.okacop078.info/PoSt/1120_622614.HtM
BbS.okacop079.info/PoSt/1120_600490.HtM
BbS.okacop080.info/PoSt/1120_883319.HtM
BbS.okacop071.info/PoSt/1120_522462.HtM
BbS.okacop072.info/PoSt/1120_315132.HtM
BbS.okacop073.info/PoSt/1120_044032.HtM
BbS.okacop074.info/PoSt/1120_282253.HtM
BbS.okacop075.info/PoSt/1120_309453.HtM
BbS.okacop076.info/PoSt/1120_265849.HtM
BbS.okacop077.info/PoSt/1120_520381.HtM
BbS.okacop078.info/PoSt/1120_910574.HtM
BbS.okacop079.info/PoSt/1120_628042.HtM
BbS.okacop080.info/PoSt/1120_643523.HtM
BbS.okacop081.info/PoSt/1120_151041.HtM
BbS.okacop082.info/PoSt/1120_092874.HtM
BbS.okacop083.info/PoSt/1120_285129.HtM
BbS.okacop084.info/PoSt/1120_509683.HtM
BbS.okacop085.info/PoSt/1120_054942.HtM
BbS.okacop086.info/PoSt/1120_223820.HtM
BbS.okacop087.info/PoSt/1120_361421.HtM
BbS.okacop088.info/PoSt/1120_160770.HtM
BbS.okacop090.info/PoSt/1120_270817.HtM
BbS.okacop091.info/PoSt/1120_799610.HtM
BbS.okacop081.info/PoSt/1120_452792.HtM
BbS.okacop082.info/PoSt/1120_154661.HtM
BbS.okacop083.info/PoSt/1120_110387.HtM
BbS.okacop084.info/PoSt/1120_839748.HtM
BbS.okacop085.info/PoSt/1120_255740.HtM
BbS.okacop086.info/PoSt/1120_559728.HtM
BbS.okacop087.info/PoSt/1120_803812.HtM
BbS.okacop088.info/PoSt/1120_267797.HtM
BbS.okacop090.info/PoSt/1120_679291.HtM
BbS.okacop091.info/PoSt/1120_529186.HtM
BbS.okacop081.info/PoSt/1120_983659.HtM
BbS.okacop082.info/PoSt/1120_772378.HtM
BbS.okacop083.info/PoSt/1120_995656.HtM
BbS.okacop084.info/PoSt/1120_303962.HtM
BbS.okacop085.info/PoSt/1120_623460.HtM
BbS.okacop086.info/PoSt/1120_382483.HtM
BbS.okacop087.info/PoSt/1120_106014.HtM
BbS.okacop088.info/PoSt/1120_238787.HtM
BbS.okacop090.info/PoSt/1120_218416.HtM
BbS.okacop091.info/PoSt/1120_873086.HtM
