明星个人网站建设方案,私人兼职做网站开发,wordpress借贷,汕头网站开发定制1 策略模式的概念
策略模式#xff08;Strategy Pattern#xff09;是 C 中常用的一种行为设计模式#xff0c;它能在运行时改变对象的行为。在策略模式中#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。
在策略模式中#xff0c;需…1 策略模式的概念
策略模式Strategy Pattern是 C 中常用的一种行为设计模式它能在运行时改变对象的行为。在策略模式中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。
在策略模式中需要创建表示各种策略的对象和一个行为随着策略对象改变而改变的 Context 对象。策略对象更改 Context 对象的执行算法。
在策略模式中通常包括以下几个角色
1策略接口Strategy Interface 定义了一个策略的公共接口所有具体的策略类都需要实现这个接口。这个接口声明了策略对象将执行的操作。
2具体策略类Concrete Strategy Classes 实现了策略接口提供了具体的算法或行为。每个具体策略类都封装了实现特定行为或算法的代码。
3上下文Context 维护一个指向策略对象的引用并定义一个接口来让策略对象执行其算法。上下文类并不知道具体的策略类它只知道策略接口。这样上下文可以将请求转发给当前关联的策略对象来执行。
2 策略模式的实现步骤
在 C 实现策略模式的实现步骤如下
1定义策略接口 首先需要定义一个策略接口。这个接口通常是一个纯虚类声明了一组公共的、需要由具体策略类来实现的方法。这些方法是策略对象将执行的行为的抽象描述。
2实现具体策略类 接下来创建实现策略接口的具体策略类。每个具体策略类都包含了实现特定算法或行为的代码。这些类继承了策略接口并实现了接口中声明的所有方法。
3创建上下文类 上下文类负责维护对策略对象的引用并定义了一个接口以便客户端代码可以通过这个接口来执行策略对象的方法。上下文类通常包含一个指向策略接口的指针或引用并通过这个指针或引用来调用策略方法。上下文类本身并不关心具体使用了哪个策略它只关心策略接口。
4在上下文中设置策略对象 在客户端代码中创建具体策略类的对象并将其传递给上下文对象。上下文对象使用这个策略对象来执行相应的算法或行为。客户端代码可以通过调用上下文类的方法来间接调用策略对象的方法。
5执行策略 客户端代码通过调用上下文类的执行方法例如 executeStrategy()来触发策略的执行。上下文类将调用当前设置的策略对象的方法实现相应的算法或行为。
6更改策略 如果需要改变行为客户端代码可以创建另一个策略对象并将其设置为上下文对象的新策略。这样上下文对象在执行策略时会使用新的算法或行为。
通过这些步骤策略模式允许在运行时动态地改变对象的行为提高了代码的灵活性和可维护性。它通过将算法和行为封装在独立的策略类中实现了算法与使用算法的客户端代码之间的解耦。这样客户端代码只需关注于如何使用策略而不需要关心策略的具体实现。
如下为样例代码
#include iostream
#include memory// 步骤1: 定义策略接口
class Strategy {
public:virtual ~Strategy() {}virtual void execute() 0;
};// 步骤2: 实现具体策略类
class ConcreteStrategyA : public Strategy {
public:void execute() override {std::cout Executing strategy A std::endl;}
};class ConcreteStrategyB : public Strategy {
public:void execute() override {std::cout Executing strategy B std::endl;}
};// 步骤3: 创建上下文类
class Context {
public:// 通过构造函数设置策略 Context(std::unique_ptrStrategy strategy) : strategy(std::move(strategy)) {}// 执行策略 void executeStrategy() {if (strategy) {strategy-execute();}else {std::cout No strategy is set. std::endl;}}// 更改策略 void setStrategy(std::unique_ptrStrategy newStrategy) {strategy std::move(newStrategy);}private:std::unique_ptrStrategy strategy; // 使用unique_ptr管理策略对象的生命周期
};// 步骤4-6: 在客户端代码中设置和执行策略
int main()
{// 创建具体策略对象并使用unique_ptr管理 auto strategyA std::make_uniqueConcreteStrategyA();auto strategyB std::make_uniqueConcreteStrategyB();// 创建上下文对象并设置初始策略 Context context(std::move(strategyA));context.executeStrategy(); // 输出Executing strategy A // 更改策略 context.setStrategy(std::move(strategyB));context.executeStrategy(); // 输出Executing strategy B // 此时strategyA和strategyB已经被unique_ptr自动释放 return 0;
}上面代码的输出为
Executing strategy A
Executing strategy B在上面代码中Strategy 是策略接口ConcreteStrategyA 和 ConcreteStrategyB 是两个实现了该接口的具体策略类。Context 类使用 std::unique_ptr 来管理策略对象的生命周期确保在不再需要时能够自动释放资源。
在 main 函数中创建了两个 std::unique_ptrStrategy 对象分别指向 ConcreteStrategyA 和 ConcreteStrategyB 的实例。然后将这些智能指针传递给 Context 对象并通过 setStrategy 方法来更改策略。每次调用 executeStrategy 方法时Context 对象都会执行当前设置的策略。
3 策略模式的应用场景
C 策略模式的应用场景主要包括以下几种情况
1算法切换 当系统需要在不同的算法之间进行切换以适应不同的性能需求时可以使用策略模式。例如排序算法在不同的场景中可能需要不同的实现策略模式可以方便地在运行时选择不同的排序算法。
2多种行为处理 如果一个对象拥有多种行为而且这些行为在实现上各不相同那么使用策略模式可以将这些行为分离到各自的策略类中从而避免在对象内部使用多重条件语句来判断执行哪种行为。这种分离可以提高代码的可读性和可维护性。
3客户端与算法解耦 当不希望客户端知道复杂的、与算法相关的数据结构时策略模式可以将算法和相关的数据结构封装在具体的策略类中从而提高算法的保密性和安全性。客户端只需要与策略接口交互而不需要关心具体的实现细节。
4动态改变行为 当需要在运行时动态地改变对象的行为时策略模式非常有用。通过更改上下文对象所持有的策略对象可以轻松地改变其行为。
3.1 策略模式应用于算法切换
以下是一个策略模式应用于算法切换的示例。在这个例子中创建一个计算器的上下文类它可以根据需要切换不同的计算策略比如加法策略和乘法策略。
#include iostream
#include memory // For std::unique_ptr // 策略接口
class CalculationStrategy {
public:virtual ~CalculationStrategy() default;virtual int calculate(int a, int b) 0;
};// 加法策略
class AdditionStrategy : public CalculationStrategy {
public:int calculate(int a, int b) override {return a b;}
};// 乘法策略
class MultiplicationStrategy : public CalculationStrategy {
public:int calculate(int a, int b) override {return a * b;}
};// 上下文类
class Calculator {
public:// 设置策略 void setStrategy(std::unique_ptrCalculationStrategy newStrategy) {strategy std::move(newStrategy);}// 执行计算 int executeCalculation(int a, int b) {if (!strategy) {throw std::runtime_error(No calculation strategy is set.);}return strategy-calculate(a, b);}private:std::unique_ptrCalculationStrategy strategy;
};int main()
{Calculator calculator;// 设置加法策略 calculator.setStrategy(std::make_uniqueAdditionStrategy());std::cout 5 3 calculator.executeCalculation(5, 3) std::endl; // 输出5 3 8 // 切换为乘法策略 calculator.setStrategy(std::make_uniqueMultiplicationStrategy());std::cout 5 * 3 calculator.executeCalculation(5, 3) std::endl; // 输出5 * 3 15 return 0;
}上面这些代码的输出为
5 3 8
5 * 3 15在这个示例中CalculationStrategy 是策略接口定义了计算的方法。AdditionStrategy 和 MultiplicationStrategy 是具体的策略类分别实现了加法和乘法。Calculator 是上下文类它持有一个指向 CalculationStrategy 的智能指针用于在运行时切换计算策略。客户端代码通过调用 setStrategy 方法来更改策略并通过 executeCalculation 方法来执行计算。
通过这种方式可以轻松地扩展新的计算策略只需要实现 CalculationStrategy 接口并在需要时将其设置为 Calculator 的策略即可。这种灵活性使得算法切换变得非常简单和直观。
3.2 策略模式应用于多种行为处理
当需要处理多种不同行为时策略模式可以通过定义一组策略类并将它们封装在接口中使得客户端代码能够根据需要选择并执行相应的行为。以下是一个策略模式应用于多种行为处理的示例
#include iostream
#include memory
#include string // 策略接口
class BehaviorStrategy {
public:virtual ~BehaviorStrategy() default;virtual void execute() 0;
};// 飞行行为
class FlyBehavior : public BehaviorStrategy {
public:void execute() override {std::cout Flying high in the sky! std::endl;}
};// 游泳行为
class SwimBehavior : public BehaviorStrategy {
public:void execute() override {std::cout Swimming in the deep blue sea! std::endl;}
};// 跑步行为
class RunBehavior : public BehaviorStrategy {
public:void execute() override {std::cout Running fast on the ground! std::endl;}
};// 上下文类
class Context {
public:// 设置行为 void setBehavior(std::unique_ptrBehaviorStrategy newBehavior) {behavior std::move(newBehavior);}// 执行当前行为 void performAction() {if (behavior) {behavior-execute();}else {std::cout No behavior is set. std::endl;}}private:std::unique_ptrBehaviorStrategy behavior;
};int main()
{Context context;// 设置飞行行为 context.setBehavior(std::make_uniqueFlyBehavior());context.performAction(); // 输出Flying high in the sky! // 切换为游泳行为 context.setBehavior(std::make_uniqueSwimBehavior());context.performAction(); // 输出Swimming in the deep blue sea! // 切换为跑步行为 context.setBehavior(std::make_uniqueRunBehavior());context.performAction(); // 输出Running fast on the ground! return 0;
}上面代码的输出为
Flying high in the sky!
Swimming in the deep blue sea!
Running fast on the ground!在这个示例中BehaviorStrategy 是策略接口定义了执行行为的方法。FlyBehavior、SwimBehavior 和 RunBehavior 是具体的策略类分别实现了不同的行为。Context 是上下文类它持有一个指向 BehaviorStrategy 的智能指针用于在运行时切换行为。客户端代码通过调用 setBehavior 方法来更改行为并通过 performAction 方法来执行当前设置的行为。
这个示例展示了策略模式在多种行为处理中的应用它使得行为的改变与客户端代码解耦从而提高了代码的可维护性和灵活性。
4 策略模式的优点与缺点
C 策略模式的优点主要包括
1灵活性 策略模式允许在运行时动态地改变对象的行为。客户端代码只需要与策略接口交互而不需要关心具体的实现细节。这使得在不需要修改现有客户端代码的情况下可以轻松地为系统添加新的行为或算法。
2开闭原则 策略模式遵循开闭原则即对扩展开放对修改封闭。通过增加新的策略类来实现新的行为而不是修改现有的类这样可以保持代码的稳定性和可维护性。
3代码复用 由于策略模式将算法或行为封装在独立的策略类中这些策略类可以被多个上下文对象复用提高了代码的复用性。
4简化单元测试 每个策略类都是独立的可以单独进行单元测试这有助于确保算法或行为的正确性并简化测试过程。
然而C 策略模式也存在一些缺点
1客户端必须了解不同策略 客户端代码需要知道有哪些策略可供选择并需要显式地设置所需的策略。这增加了客户端代码的复杂性并可能导致策略选择的错误。
2策略类数量可能增加 随着系统中策略数量的增加可能需要创建大量的策略类。这可能导致代码库变得庞大和难以管理。
3性能开销 由于策略模式涉及到虚函数调用和可能的动态内存分配如果使用智能指针管理策略对象因此在性能敏感的场合可能会引入一定的开销。然而这种开销通常与策略模式的灵活性相比是可以接受的。
4额外的接口设计 设计良好的策略接口需要一定的经验和技巧。如果接口设计不当可能会导致策略类之间的耦合度过高违背了策略模式的初衷。
综上所述C策略模式在提供灵活性和可维护性的同时也可能带来一些额外的复杂性和性能开销。因此在决定是否使用策略模式时需要根据具体的应用场景和需求进行权衡。