1、策略模式概述:
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户端。
策略模式包括以下角色:
- 环境类(Context):维护一个策略对象的引用,用于调用具体的策略。
- 抽象策略类(Strategy):定义所有具体策略的公共接口。
- 具体策略类(ConcreteStrategy):实现具体策略的行为。
2、策略模式的适用场景:
- 当需要在不同情况下使用不同的算法或行为时。
- 当需要将算法的定义与使用分离,以便于算法的独立开发和优化。
- 当需要消除一些条件语句,提高代码的可维护性和可读性。
3、策略模式的优点:
- 算法和客户端代码解耦,使得算法可以独立于客户端进行优化和扩展。
- 提高了代码的可维护性,可以很容易地替换和添加新的策略。
- 可以避免使用多重条件选择语句,提高代码的可读性。
举例说明:假设我们正在开发一个导航系统,需要根据不同的交通工具(如步行、自行车、公交车、汽车)提供不同的路线规划策略。通过使用策略模式,我们可以将各种路线规划算法封装成不同的策略类,从而使得导航系统的核心代码与这些算法解耦,便于后续优化和扩展。
4、策略模式的缺点:
- 客户端必须知道所有的策略类,并根据不同情况选择合适的策略。这可能会增加客户端的复杂性。
- 可能会导致系统中存在大量的策略类,增加系统的复杂性。
举例说明:在前面的导航系统例子中,如果有很多种不同的交通工具和路线规划策略,那么策略模式可能会导致大量的策略类,使系统变得复杂。此外,客户端需要知道所有的策略类并在不同情况下选择
5、用C++实现一个策略模式例子:
首先,我们定义抽象策略类Strategy,包含一个纯虚函数execute(),用于执行具体的策略:
#include <iostream>
// 抽象策略类
class Strategy {
public:
virtual void execute() const = 0;
virtual ~Strategy() = default;
};
然后,我们创建两个具体策略类ConcreteStrategyA和ConcreteStrategyB,分别实现execute()函数:
// 具体策略类A
class ConcreteStrategyA : public Strategy {
public:
void execute() const override {
std::cout << "Executing strategy A." << std::endl;
}
};
// 具体策略类B
class ConcreteStrategyB : public Strategy {
public:
void execute() const override {
std::cout << "Executing strategy B." << std::endl;
}
};
接下来,我们定义环境类Context,它将维护一个策略对象的引用,并提供一个setStrategy()函数来设置具体的策略。此外,Context还提供了一个executeStrategy()函数,用于调用具体策略的execute()函数:
// 环境类
class Context {
private:
const Strategy* strategy_;
public:
Context() : strategy_(nullptr) {}
~Context() { delete strategy_; }
void setStrategy(const Strategy* strategy) {
delete strategy_;
strategy_ = strategy;
}
void executeStrategy() const {
if (strategy_) {
strategy_->execute();
} else {
std::cout << "No strategy is set." << std::endl;
}
}
};
最后,我们在main()函数中创建一个Context对象,然后根据需要设置和执行不同的策略:
int main() {
Context context;
// 使用具体策略A
context.setStrategy(new ConcreteStrategyA());
context.executeStrategy();
// 使用具体策略B
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy();
return 0;
}
这个示例展示了如何使用策略模式将算法和客户端代码解耦。通过使用环境类Context,我们可以方便地切换和执行不同的策略,而无需修改客户端代码。