策略模式的定义
策略模式属于对象的行为模式,使得算法可以在不影响到客户端的情况下发生变化。
将算法的逻辑抽象接口封装到一个类中,再通过委托的方式将具体的算法实现委托给具体的策略类来实现。
原则:
分离变化部分,封装接口,基于接口编程各种功能。此模式让行为的变化独立于算法的使用者。
策略模式的相关概念
- 上下文(Context)维护指向具体策略的引用,且仅通过策略接口与该对象进行交流。
- 策略(Strategy)接口是所有具体策略的通用接口,它声明了一个上下文用于执行策略的方法。
- 具体策略(Concrete Strategies)实现了上下文所用算法的各种不同变体。
- 当上下文需要运行算法时,它会在其已连接的策略对象上调用执行方法。上下文不清楚其所涉及的策略类型与算法的执行方式。
- 客户端(Client)会创建一个特定策略对象并将其传递给上下文。上下文则会提供一个设置器以便客户端在运行时替换相关联的策略。
策略模式的角色扮演
- 抽象策略角色(Strategy): 抽象策略类。
- 具体策略角色(ConcreteStrategy):封装了继续相关的算法和行为。
- 环境角色(Context):持有一个策略类的引用,最终给客户端调用。
策略模式的优缺点
优点:
- 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护。
- 策略模式让你可以动态的改变对象的行为,动态修改策略。
- 你可以将算法的实现和使用算法的代码隔离开来。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 类过多—策略模式造成很多的策略类,每个具体策略类都会产生一个新类。(这点可以通过享元模式来克服类过多)
策略模式的实现方法
- 从上下文类中找出修改频率较高的算法(也可能是用于在运行时选择某个算法变体的复杂条件运算符)。
- 声明该算法所有变体的通用策略接口。
- 将算法逐一抽取到各自的类中,它们都必须实现策略接口。
- 在上下文类中添加一个成员变量用于保存对于策略对象的引用。然后提供设置器以修改该成员变量。上下文仅可通过策略接口同策略对象进行交互,如有需要还可定义一个接口来让策略访问其数据。
- 客户端必须将上下文类与相应策略进行关联,使上下文可以预期的方式完成其主要工作。
策略模式的适用场景
- 当你想使用对象中各种不同的算法变体,并希望能在运行时切换算法时,可使用策略模式。
策略模式让你能够将对象关联至可以不同方式执行特定子任务的不同子对象,从而以间接方式在运行时更改对象行为。
- 当你有许多仅在执行某些行为时略有不同的相似类时,可使用策略模式。
策略模式让你能将不同行为抽取到一个独立类层次结构中,并将原始类组合成同一个,从而减少重复代码。
- 如果算法在上下文的逻辑中不是特别重要,使用该模式能将类的业务逻辑与其算法实现细节隔离开来。
策略模式让你能将各种算法的代码、内部数据和依赖关系与其他代码隔离开来。不同客户端可通过一个简单接口执行算法,并能在运行时进行切换。
- 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时,可使用该模式。
策略模式将所有继承自同样接口的算法抽取到独立类中,因此不再需要条件语句。 原始对象并不实现所有算法的变体,而是将执行工作委派给其中的一个独立算法对象。
策略模式的代码示例
//1.抽象算法类 class algorithm{ public: virtual int operation(int,int) = 0; } /****************************************************************************************/ //2.具体算法类 #pragma once #include <vector> #include <iostream> class addition: public algorithm { public: int operation(vector<int> & operands){ return (operandA + operandB); } } //减法 class substruction: public algorithm { public: int operation(int operandA,int operandB){ return (operandA - operandB); } }
#include <iostream> #include <memory> #include <vector> #include <algorithm> #include <functional> #include <optional> // 移动策略接口 class MoveStrategy { public: virtual ~MoveStrategy() = default; virtual void move() const = 0; }; // 行走策略 class WalkStrategy final : public MoveStrategy { public: void move() const override { std::cout << "Walking..." << std::endl; } }; // 飞行策略 class FlyStrategy final : public MoveStrategy { public: void move() const override { std::cout << "Flying..." << std::endl; } }; // 环境类 class Robot { public: void set_move_strategy(std::unique_ptr<MoveStrategy> strategy) { move_strategy = std::move(strategy); } void execute_move_strategy() const { if (move_strategy) { move_strategy->move(); } else { std::cout << "No move strategy set." << std::endl; } } private: std::unique_ptr<MoveStrategy> move_strategy; }; int main() { Robot robot; // 使用智能指针和多态创建策略对象 auto walk_strategy = std::make_unique<WalkStrategy>(); auto fly_strategy = std::make_unique<FlyStrategy>(); // 使用lambda表达式创建简单的命令 auto command_set = std::vector<std::function<void()>>{ [&robot, &walk_strategy] { robot.set_move_strategy(std::move(walk_strategy)); }, [&robot, &fly_strategy] { robot.set_move_strategy(std::move(fly_strategy)); }, [&robot] { robot.execute_move_strategy(); }}; // 遍历命令并执行 for (const auto& command : command_set) { command(); } return 0; }