什么是策略模式?
策略模式 是一种行为型设计模式,它让你能在运行时 动态地改变对象的行为 。
它的核心思想是:把算法(或行为)封装成独立的类,让它们可以互相替换。
比如:一个游戏角色可以有多种攻击方式(近战、远程、魔法),你希望在游戏运行时切换攻击方式,而不是写死在代码里。
🚫 不使用策略模式的写法(硬编码)
假设我们要实现一个"鸭子"类,不同鸭子有不同的飞行方式。
// 不使用策略模式
#include <iostream>
using namespace std;
class Duck {
public:
void quack() {
cout << "嘎嘎叫" << endl;
}
// 飞行方式被写死在类里
virtual void fly() {
cout << "用翅膀飞" << endl;
}
};
class RubberDuck : public Duck {
public:
// 橡皮鸭不会飞!
void fly() override {
cout << "我不会飞 😢" << endl;
}
};
class MallardDuck : public Duck {
// 绿头鸭正常飞
};
int main() {
Duck* d1 = new MallardDuck();
Duck* d2 = new RubberDuck();
d1->fly(); // 输出:用翅膀飞
d2->fly(); // 输出:我不会飞 😢
delete d1;
delete d2;
return 0;
}
❌ 缺点:
- 代码重复 :如果有一百种鸭子,每种飞法不同,就要写一百个
fly()。 - 难以复用:比如"火箭推进飞行"只能在一个鸭子里用,不能共享给其他需要火箭飞的角色(比如机器人)。
- 违反开闭原则:想加新飞行方式?必须修改或继承 Duck 类,容易出错。
✅ 使用策略模式的写法
我们把"飞行行为"抽出来,变成独立的接口(抽象类),然后让不同飞行方式实现它。
#include <iostream>
using namespace std;
// ========= 策略接口 =========
class FlyBehavior {
public:
virtual ~FlyBehavior() = default;
virtual void fly() = 0;
};
// ========= 具体策略 =========
class FlyWithWings : public FlyBehavior {
public:
void fly() override {
cout << "用翅膀飞 🕊️" << endl;
}
};
class FlyNoWay : public FlyBehavior {
public:
void fly() override {
cout << "我不会飞 😢" << endl;
}
};
class FlyWithRocket : public FlyBehavior {
public:
void fly() override {
cout << "用火箭飞 🚀" << endl;
}
};
// ========= 上下文(Duck) =========
class Duck {
protected:
FlyBehavior* flyBehavior; // 指向策略的指针
public:
Duck(FlyBehavior* fb) : flyBehavior(fb) {}
void setFlyBehavior(FlyBehavior* fb) {
flyBehavior = fb; // 运行时可换策略!
}
void performFly() {
flyBehavior->fly(); // 委托给策略
}
void quack() {
cout << "嘎嘎叫" << endl;
}
};
// 具体鸭子
class MallardDuck : public Duck {
public:
MallardDuck() : Duck(new FlyWithWings()) {}
};
class RubberDuck : public Duck {
public:
RubberDuck() : Duck(new FlyNoWay()) {}
};
// 甚至可以给机器人用!
class Robot {
private:
FlyBehavior* flyBehavior;
public:
Robot(FlyBehavior* fb) : flyBehavior(fb) {}
void launch() { flyBehavior->fly(); }
};
// ========= 主函数 =========
int main() {
Duck* duck1 = new MallardDuck();
Duck* duck2 = new RubberDuck();
duck1->performFly(); // 用翅膀飞 🕊️
duck2->performFly(); // 我不会飞 😢
// 动态更换策略!
duck2->setFlyBehavior(new FlyWithRocket());
duck2->performFly(); // 用火箭飞 🚀
// 火箭飞行策略还能给机器人用!
Robot robot(new FlyWithRocket());
robot.launch(); // 用火箭飞 🚀
// 注意:这里简化了内存管理,实际建议用智能指针
delete duck1;
delete duck2;
return 0;
}
✅ 使用策略模式的优点
| 优点 | 说明 |
|---|---|
| 解耦 | 行为(策略)和主体(Duck)分离,各自独立变化 |
| 可复用 | 同一个飞行策略可以用在鸭子、机器人、飞机等任何地方 |
| 易于扩展 | 加新飞行方式?只需新增一个 FlyBehavior 子类,无需改 Duck |
| 运行时切换 | 可以在程序运行中动态改变行为(比如游戏中升级武器) |
| 符合开闭原则 | 对扩展开放,对修改关闭 |
⚠️ 缺点(也要知道)
- 类数量增多:每个策略都是一个类,小型项目可能显得"过度设计"。
- 客户端需了解策略:调用者要知道有哪些策略可用(不过可通过工厂模式缓解)。
- 内存管理稍复杂 :涉及指针/动态分配(C++ 中建议用
std::unique_ptr管理)。
🔚 总结一句话:
策略模式 = 把"怎么做"从"谁来做"里抽出来,变成可插拔的模块。
就像你手机的充电线:USB-C、Lightning、Micro USB 是不同的"策略",手机(上下文)只要支持换线,就能适配不同充电方式!