一、策略模式简介
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,将每一个算法封装起来,并使它们可以相互替换。具体的算法选择交由客户端决定,即不同的算法可以在运行时动态地(平滑地)进行替换和管理。
策略:根据形势发展而制定的行动方针和斗争方法;泛指善于灵活运用适当 '眼下情况下的' 斗争方式和方法。
策略模式的结构图
策略模式的组成
- 上下文(Context):持有一个策略的引用,并且可以在运行时更换策略。
- 策略接口(Strategy):定义了一个公共的接口,所有的具体策略都实现这个接口。
- 具体策略(ConcreteStrategy):实现了策略接口的具体算法。
二、策略模式的设计方法
使用策略模式设计《36计》的23种计策,每一种计策设计成一个单独的类,模拟每一个策略的行为(字符描述)。
strategy.cpp
#include <iostream>
#include <memory>
#include <map>
#include <string>
// 策略接口
class Strategy {
public:
virtual ~Strategy() = default;
virtual void execute() const = 0;
};
// 具体策略
class Strategy1 : public Strategy {
public:
void execute() const override {
std::cout << "掩盖真实意图,混淆敌人视线,以达到自己的目的。" << std::endl;
}
};
class Strategy2 : public Strategy {
public:
void execute() const override {
std::cout << "利用第三方的力量或资源来打击目标。" << std::endl;
}
};
class Strategy3 : public Strategy {
public:
void execute() const override {
std::cout << "让敌人疲惫,自己则采取相对轻松的状态来应对。" << std::endl;
}
};
class Strategy4 : public Strategy {
public:
void execute() const override {
std::cout << "在敌人危机时刻,乘机夺取利益。" << std::endl;
}
};
class Strategy5 : public Strategy {
public:
void execute() const override {
std::cout << "制造假象,引诱敌人到错误的方向上。" << std::endl;
}
};
class Strategy6 : public Strategy {
public:
void execute() const override {
std::cout << "制造虚假信息或虚构情况,迷惑敌人。" << std::endl;
}
};
class Strategy7 : public Strategy {
public:
void execute() const override {
std::cout << "秘密行动,绕过敌人的防线。" << std::endl;
}
};
class Strategy8 : public Strategy {
public:
void execute() const override {
std::cout << "表面友善,实则暗中图谋。" << std::endl;
}
};
class Strategy9 : public Strategy {
public:
void execute() const override {
std::cout << "顺势而为,趁机获得附带利益。" << std::endl;
}
};
class Strategy10 : public Strategy {
public:
void execute() const override {
std::cout << "通过小动作试探敌人反应,暴露敌人的真实意图。" << std::endl;
}
};
class Strategy11 : public Strategy {
public:
void execute() const override {
std::cout << "引开敌人,使其离开本来的位置或目标。" << std::endl;
}
};
class Strategy12 : public Strategy {
public:
void execute() const override {
std::cout << "暂时放松对目标的控制,诱使其主动暴露。" << std::endl;
}
};
class Strategy13 : public Strategy {
public:
void execute() const override {
std::cout << "用小的代价吸引敌人,为获取更大利益做铺垫。" << std::endl;
}
};
class Strategy14 : public Strategy {
public:
void execute() const override {
std::cout << "根据实际情况灵活应对,采取适当的行动。" << std::endl;
}
};
class Strategy15 : public Strategy {
public:
void execute() const override {
std::cout << "全面考虑局势,制定整体计划。" << std::endl;
}
};
class Strategy16 : public Strategy {
public:
void execute() const override {
std::cout << "客人反过来成为主人,掌握主动权。" << std::endl;
}
};
class Strategy17 : public Strategy {
public:
void execute() const override {
std::cout << "虚晃一招,使敌人判断错误,然后在另一方发起攻击。" << std::endl;
}
};
class Strategy18 : public Strategy {
public:
void execute() const override {
std::cout << "直接攻击敌人的首领,瓦解其指挥系统。" << std::endl;
}
};
class Strategy19 : public Strategy {
public:
void execute() const override {
std::cout << "以替代品欺骗敌人,保全自身利益。" << std::endl;
}
};
class Strategy20 : public Strategy {
public:
void execute() const override {
std::cout << "在安全距离观察敌人行动,吃瓜群众。" << std::endl;
}
};
class Strategy21 : public Strategy {
public:
void execute() const override {
std::cout << "通过攻击敌人的其他重要目标,迫使敌人撤退。" << std::endl;
}
};
class Strategy22 : public Strategy {
public:
void execute() const override {
std::cout << "在无胜算的情况下,选择撤退以保存实力。" << std::endl;
}
};
class Strategy23 : public Strategy {
public:
void execute() const override {
std::cout << "抓住敌人的致命弱点,进行精准打击。" << std::endl;
}
};
// 上下文
class Context {
public:
Context(std::unique_ptr<Strategy> strategy) : strategy(std::move(strategy)) {}
void setStrategy(std::unique_ptr<Strategy> newStrategy) {
strategy = std::move(newStrategy);
}
void executeStrategy() const {
strategy->execute();
}
private:
std::unique_ptr<Strategy> strategy;
};
// 策略工厂
class StrategyFactory {
public:
using StrategyCreator = std::unique_ptr<Strategy>(*)();
static StrategyFactory& getInstance() {
static StrategyFactory instance;
return instance;
}
void registerStrategy(const std::string& name, StrategyCreator creator) {
creators[name] = creator;
}
std::unique_ptr<Strategy> createStrategy(const std::string& name) const {
auto it = creators.find(name);
if (it != creators.end()) {
return it->second();
}
return nullptr;
}
private:
std::map<std::string, StrategyCreator> creators;
};
// 注册策略
#define REGISTER_STRATEGY(name, strategyClass) \
namespace { \
const bool registered_##strategyClass = \
(StrategyFactory::getInstance().registerStrategy(name, []() -> std::unique_ptr<Strategy> { \
return std::make_unique<strategyClass>(); \
}), true); \
}
// 注册所有策略
REGISTER_STRATEGY("瞒天过海", Strategy1)
REGISTER_STRATEGY("借刀杀人", Strategy2)
REGISTER_STRATEGY("以逸待劳", Strategy3)
REGISTER_STRATEGY("趁火打劫", Strategy4)
REGISTER_STRATEGY("声东击西", Strategy5)
REGISTER_STRATEGY("无中生有", Strategy6)
REGISTER_STRATEGY("暗渡陈仓", Strategy7)
REGISTER_STRATEGY("笑里藏刀", Strategy8)
REGISTER_STRATEGY("顺手牵羊", Strategy9)
REGISTER_STRATEGY("打草惊蛇", Strategy10)
REGISTER_STRATEGY("调虎离山", Strategy11)
REGISTER_STRATEGY("欲擒故纵", Strategy12)
REGISTER_STRATEGY("抛砖引玉", Strategy13)
REGISTER_STRATEGY("见机行事", Strategy14)
REGISTER_STRATEGY("统筹全局", Strategy15)
REGISTER_STRATEGY("反客为主", Strategy16)
REGISTER_STRATEGY("声东击西", Strategy17)
REGISTER_STRATEGY("擒贼擒王", Strategy18)
REGISTER_STRATEGY("李代桃僵", Strategy19)
REGISTER_STRATEGY("隔岸观火", Strategy20)
REGISTER_STRATEGY("围魏救赵", Strategy21)
REGISTER_STRATEGY("三十六计,走为上策", Strategy22)
REGISTER_STRATEGY("打蛇打七寸", Strategy23)
// 注册更多策略...
// 客户端
int main() {
// 客户选择策略
std::string strategyName;
std::cout << "请选择您的策略(方案): ";
std::cin >> strategyName;
// 从工厂创建策略
auto strategy = StrategyFactory::getInstance().createStrategy(strategyName);
if (strategy) {
Context context(std::move(strategy));
context.executeStrategy();
} else {
std::cout << "您的36计不存在策略--->"<< strategyName << " ,请纠正或补充哦! " << std::endl;
}
return 0;
}
运行效果
三、策略模式的应用场景
1. 需要在运行时选择算法或策略
当你的应用程序需要根据不同的条件选择不同的算法或策略时,策略模式可以帮助你将这些算法封装到独立的策略类中,从而在运行时动态地选择和切换策略。例如:
- 排序算法选择:在一个排序工具中,你可能需要根据数据的大小或性质选择不同的排序算法(如快速排序、归并排序、插入排序等)。
- 支付处理:一个电商系统可能需要支持多种支付方式(如信用卡、PayPal、银行转账等),用户可以选择不同的支付策略进行支付。
2. 系统中有多个类似的变体
当系统中存在多个类似的变体,且这些变体的行为仅在某些方面有所不同时,策略模式可以帮助你将这些变体的具体实现分离到不同的策略类中。例如:
- 游戏角色行为:在游戏中,角色可能有不同的攻击策略(如近战攻击、远程攻击、魔法攻击等),这些策略可以作为独立的策略类来实现。
- 图形渲染:在图形渲染系统中,可以使用不同的渲染策略(如2D渲染、3D渲染、光线追踪等)来处理不同的渲染需求。
3. 需要避免条件语句
当你发现自己在一个类中使用大量的条件语句(如
if-else
或switch
语句)来选择不同的行为时,策略模式可以帮助你简化代码,将这些条件语句移到策略类中。例如:
- 文本格式化:一个文档处理程序可能需要根据不同的格式要求(如 Markdown、HTML等)格式化文本。可以使用策略模式来替代复杂的条件判断。
- 数据压缩:在一个数据处理系统中,根据不同的压缩要求(如 ZIP、RAR、GZIP 等)进行数据压缩时,策略模式可以帮助减少条件语句的使用。
4. 需要动态改变行为
当一个对象的行为在运行时可能会发生变化时,策略模式可以帮助你在对象的生命周期内动态改变其行为。例如:
- 工作流引擎:在一个工作流系统中,工作流的处理方式可能会随着状态的变化而变化。可以使用策略模式来处理不同的工作流阶段。
- 文本校验:在用户输入验证的系统中,可以根据不同的输入类型或验证规则(如电子邮件验证、电话号码验证、用户名验证等)动态选择不同的校验策略。
5. 需要增强可维护性和扩展性
当系统需要经常添加新的策略或修改现有策略时,策略模式提供了一种优雅的方式来增强系统的可维护性和扩展性。例如:
- 插件系统:在一个插件系统中,可以使用策略模式来管理不同的插件功能,每个插件都可以作为一个策略来实现。
- 报表生成:在报表生成系统中,可以使用策略模式来支持不同类型的报表格式(如 PDF、Excel、CSV 等),便于未来添加新的报表格式。
四、总结
策略模式中,每一种算法都被单独的封装成一个策略,客户端通过上下文(Context)平滑地切换不同的算法类。简单来说策略模式就好比向客户提供多种可选方案,让客户自主选择需要执行哪种方案(具体算法类);他的优点也是其缺点,如果客户想根据自身的实际情况选择哪种方案,就必须了解提供的所有可选方案(算法类)的区别。意味着客户需具有统筹全局和精湛专业的能力,以便适时选择恰当的方案(算法类)。