一.策略模式
策略模式(Strategy Pattern)是一种行为设计模式,用于将算法家族(一组相似的算法)封装起来,使它们可以相互替换,让算法的变化独立于使用算法的客户端。
1.优点
- 提高代码的灵活性和可维护性,将算法的变化独立于使用算法的客户端,客户端可以在运行时动态地改变算法的行为,而不必修改算法的实现。
- 避免大量的if-else或switch-case语句,提高了代码的可读性和可维护性。使用策略模式可以将复杂的条件分支结构转化为简单的对象聚合关系,从而使得代码更加清晰简洁。
- 方便增加、删除或替换算法,策略模式提供了一种可扩展的方式来定义算法族,这对于需要频繁地增加新的算法或调整算法的应用场景较有用。
2.缺点
- 策略如果很多的话,会造成策略类膨胀;
- 使用者必须清楚所有的策略类及其用途;
3.适用场景
- 多种算法可供选择:当一个问题可以有多种解决算法时,可以使用策略模式将每种算法封装成独立的策略类,从而使得客户端可以动态地选择使用哪种算法。
- 需要动态切换算法:当需要根据不同的情况使用不同的算法时,可以使用策略模式将每种算法封装成独立的策略类,然后通过动态设置策略对象的方式,实现算法的动态切换。
- 需要对算法进行扩展:当需要新增一种算法时,可以通过增加一个新的策略类来实现扩展,而不必修改客户端的代码,从而降低了修改代码的风险。
- 需要将算法实现类与客户端分离:当算法实现类过于复杂或者客户端与算法实现类之间的耦合度过高时,可以使用策略模式将算法实现类封装成独立的策略类,从而降低了客户端与算法实现类之间的耦合度。
- 需要避免大量的条件语句:当客户端需要根据某个条件来选择不同的算法时,如果使用大量的条件语句来实现,代码会变得非常臃肿和难以维护。这时候可以使用策略模式将每种算法封装成独立的策略类,从而避免了大量的条件语句。
例如:
- 排序算法:排序算法有很多种,如快速排序、归并排序、插入排序等。可以使用策略模式将每种排序算法封装成独立的策略类,从而使得客户端可以动态地选择使用哪种排序算法。
- 支付方式:在电商网站上,用户可以选择多种支付方式,如支付宝、微信支付、银联支付等。可以使用策略模式将每种支付方式封装成独立的策略类,从而使得客户端可以动态地选择使用哪种支付方式。
- 游戏角色技能:在游戏中,不同的角色有不同的技能,如战士可以使用狂暴技能、法师可以使用火球术等。可以使用策略模式将每种技能封装成独立的策略类,从而使得角色可以动态地选择使用哪种技能。
- 数据库访问方式:在开发中,可能需要使用不同的数据库访问方式,如使用 JDBC、Hibernate、MyBatis 等。可以使用策略模式将每种访问方式封装成独立的策略类,从而使得客户端可以动态地选择使用哪种访问方式。
- 策略游戏中的AI:在策略游戏中,不同的AI可能有不同的策略,如攻击型 AI 可能会优先攻击敌方的防御建筑,而防御型 AI可能会优先升级自己的防御建筑。可以使用策略模式将每种 AI 的策略封装成独立的策略类,从而使得游戏可以动态地选择使用哪种 AI。
二.C++程序示例
1.策略模式结构要素
- 策略接口(Strategy Interface):定义了一系列算法的公共接口,所有具体策略都要实现这个接口。
- 具体策略类(Concrete Strategy Class):实现了策略接口,提供具体的算法实现。
- 环境类(Context Class):持有一个策略对象的引用,提供对外的访问接口,可以动态地设置和切换策略对象。
- 客户端(Client):使用策略模式的地方,通过环境类访问不同的策略对象,完成具体的业务逻辑。
2.C++程序示例
#include <iostream>
using namespace std;
// 定义策略接口
class Strategy {
public:
virtual void execute() = 0;
};
// 具体策略类 A
class ConcreteStrategyA : public Strategy {
public:
void execute() {
cout << "Execute strategy A" << endl;
}
};
// 具体策略类 B
class ConcreteStrategyB : public Strategy {
public:
void execute() {
cout << "Execute strategy B" << endl;
}
};
// 环境类
class Context {
private:
Strategy* strategy; // 持有策略对象的引用
public:
Context(Strategy* s) : strategy(s) {}
void setStrategy(Strategy* s) {
strategy = s;
}
void executeStrategy() {
strategy->execute();
}
};
int main() {
// 创建具体策略对象
ConcreteStrategyA* strategyA = new ConcreteStrategyA();
ConcreteStrategyB* strategyB = new ConcreteStrategyB();
// 创建环境对象并设置策略对象 A
Context* context = new Context(strategyA);
context->executeStrategy();
// 动态切换策略对象为 B 并执行
context->setStrategy(strategyB);
context->executeStrategy();
// 释放资源
delete strategyA;
delete strategyB;
delete context;
return 0;
}
- Strategy 定义了策略接口,所有具体策略都要实现该接口。
- ConcreteStrategyA 和 ConcreteStrategyB 分别是具体的策略类,实现了不同的算法。
- Context 是环境类,持有一个策略对象的引用,提供对外的访问接口,并可以动态地设置和切换策略对象。
- Client 是使用策略模式的地方,通过环境类访问不同的策略对象,完成具体的业务逻辑。