当前位置: 首页 > news >正文

【C++设计模式之Strategy策略模式】

C++设计模式之Strategy策略模式

  • 模式定义
  • 核心思想
  • 动机(Motivation)
  • 结构(Structure)
  • 实现步骤
    • 1. 定义策略接口(基于继承)
    • 2.实现具体策略
    • 3.上下文类(Context)
    • 4. 在main中调用
  • 应用场景(基于继承)
    • 1.定义策略接口
    • 2.实现具体策略
    • 3.上下文类(Context)
    • 4.在main中调用测试
  • 现代 C++ 优化(基于 std::function)
    • 1.使用函数对象替代接口
    • 2.定义策略函数
    • 3.main.cpp中使用示例
  • 优化方向
    • 1.编译时策略(模板实现)
    • 2.线程安全策略切换
  • 要点总结


模式定义

策略模式:定义一系列算法,把她们一个个封装起来,并且使它们可以相互替换(变化)。该模式使得算法可以独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
需要区分策略模式和之前提到的模板方法模式的不同,模板方法是通过继承来改变部分步骤,而策略模式是通过组合不同的策略对象来改变整体行为。

核心思想

  • 解耦算法与客户端:将算法逻辑从主类中分离,避免代码臃肿。
  • 运行时动态切换:通过更换策略对象,灵活改变程序行为。
  • 开闭原则:新增算法无需修改现有代码,只需添加新策略类。

动机(Motivation)

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
  • 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

结构(Structure)

在这里插入图片描述

实现步骤

1. 定义策略接口(基于继承)

startegy.h

#pragma once
class Strategy {//策略模式的运算法则
public:virtual ~Strategy() {}virtual void doSomething() = 0;
};

2.实现具体策略

concretestrategy.h

#pragma once
#include<iostream>
#include"strategy.h"
class ConcreteStrategy1 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy1 doSomething" << std::endl;}
};class ConcreteStrategy2 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy2 doSomething" << std::endl;}
};

3.上下文类(Context)

持有策略对象的引用,并委托算法执行

context.h

#pragma once
#include"strategy.h"
class Context {
public://构造函数设置具体策略Context(Strategy *strategy) {strategy_ = strategy;}//封装后的策略方法void doAnything() {strategy_->doSomething();}private:Strategy *strategy_ = nullptr;
};

4. 在main中调用

#include "concretestrategy.h"
#include "context.h"int main()
{Strategy *strategy = new ConcreteStrategy1();//声明上下文对象Context context(strategy);context.doAnything();delete strategy;
}

应用场景(基于继承)

传统实现(基于继承),实现快速排序算法,归并排序算法的策略模式

1.定义策略接口

sortingstrategy.h

#pragma once
#include<iostream>
#include<vector>//策略接口:定义算法的抽象操作
class SortingStrategy {
public:virtual ~SortingStrategy() = default;virtual void sort(std::vector<int>&data)const = 0;
};

2.实现具体策略

#pragma once
#include"sortingstrategy.h"
//具体策略1:快速排序
class QuickSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with QuickSort\n";//快速排序具体实现}
};class MergeSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with MergeSort\n";//归并排序具体实现}
};

3.上下文类(Context)

持有策略对象的引用,并委托算法执行

context.h

#pragma once
#include"concretesorting.h"
class Sorter {
private:std::unique_ptr<SortingStrategy> strategy_;  //使用智能指针管理策略对象public:explicit Sorter(std::unique_ptr<SortingStrategy> strategy):strategy_(std::move(strategy)){}//动态切换策略void setStrategy(std::unique_ptr<SortingStrategy>strategy) {strategy_ = std::move(strategy);}//执行排序void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_->sort(data);}}
};

4.在main中调用测试

#include"context.h"
#include<vector>int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(std::make_unique<QuickSort>());sorter.executeSort(data);    //输出:Sorting with QuickSortsorter.setStrategy(std::make_unique<MergeSort>());sorter.executeSort(data);    //输出Sorting with MergeSortreturn 0;
}

现代 C++ 优化(基于 std::function)

1.使用函数对象替代接口

无需继承策略接口,直接通过std::function封装算法:
context.h

#pragma once
#include<functional>
#include<vector>class Sorter {
public:using Strategy = std::function<void(std::vector<int>&)>;explicit Sorter(Strategy strategy):strategy_(std::move(strategy)){}void setStrategy(Strategy strategy) {strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_(data);}}private:Strategy strategy_;
};

2.定义策略函数

context.h

void quickSort(std::vector<int>& data) {std::cout << "Sorting with QuickSort\n";// 快速排序实现...
}void mergeSort(std::vector<int>& data) {std::cout << "Sorting with MergeSort\n";// 归并排序实现...
}// 支持 Lambda 表达式
auto bubbleSort = [](std::vector<int>& data) {std::cout << "Sorting with BubbleSort\n";// 冒泡排序实现...
};

3.main.cpp中使用示例

#include"context.h"int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(quickSort);sorter.executeSort(data);      //输出Sorting with QuickSortsorter.setStrategy(mergeSort); //输出Sorting with MergeSortsorter.executeSort(data);sorter.setStrategy(bubbleSort);//输出Sorting with BubbleSortsorter.executeSort(data);//直接传达Lambdasorter.setStrategy([](std::vector<int>&data) {std::cout << "Custom Lambda Strategy \n";});sorter.executeSort(data);return 0;
}

优化方向

1.编译时策略(模板实现)

通过模板参数在编译时绑定 策略,消除运行时开销:

#pragma once
#include<vector>
#include<iostream>template<typename Strategy>
class ComplieTimeSorter {
public:void executeSort(std::vector<int>&data)const {Strategy::sort(data);   //策略需要提供静态方法}
};//策略类无需继承接口
struct QuickSort {static void sort(std::vector<int>&data) {std::cout << "Compile-Time QuickSort \n";}
};int main()
{std::vector<int> data = { 5,2,7,1,9 };ComplieTimeSorter<QuickSort>sorter;sorter.executeSort(data);  //输出Complie-Time QuickSortsystem("pause");return 0;
}

2.线程安全策略切换

在多线程环境中安全且策略:

#pragma once
#include<mutex>
#include<vector>class ThreadSafeSorter {
public:using Strategy = std::function<void(std::vector<int>&)>;void setStrategy(Strategy strategy) {std::lock_guard<std::mutex>lock(mtx_);strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {std::lock_guard<std::mutex>lock(mtx_);if (strategy_) {strategy_(data);}}
private:mutable std::mutex mtx_;Strategy strategy_;
};

要点总结

  • Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
  • Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
  • 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

相关文章:

  • 学习心得《How Global AI Policy and Regulations Will Impact Your Enterprise》Gartner
  • 文本框碰撞测试
  • C++AVL树
  • 访问网页的全过程(分步骤的详细解析)
  • 通过Linux系统服务管理IoTDB集群的高效方法
  • C++ -- string
  • C++:求分数序列和
  • 强化学习PPO算法学习记录
  • 【Pandas】pandas DataFrame clip
  • GET请求如何传复杂数组参数
  • 使用oracle goldengate同步postgresql到postgresql
  • Eclipse SWT 1 等比缩放
  • Web端项目系统访问页面很慢,后台数据返回很快,网络也没问题,是什么导致的呢?
  • 文件包含2
  • OpenCV的 ccalib 模块用于自定义标定板的检测和处理类cv::ccalib::CustomPattern()----函数calibrate
  • 火山引擎火山云主推产品
  • wpf UserControl 更换 自定义基类
  • PX4开始之旅(一)自动调参
  • Windows10 本地部署 IPFS(go-ipfs)
  • NX884NX891美光固态闪存NX895NX907
  • 中国词学研究会原会长、华东师大教授马兴荣逝世,享年101岁
  • 数理+AI+工程,上海交大将开首届“笛卡尔班”招生约20名
  • 美英达成贸易协议,美股集体收涨
  • 越秀地产前4个月销售额约411.2亿元,达年度销售目标的34.1%
  • 宁合两大都市圈交汇之城含山:要想身体好,常往含山跑
  • 水中托举救出落水孩童后遇难,42岁退役军人高武被确认为见义勇为