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

C++设计模式--策略模式与观察者模式

       

目录

观察者模式

策略模式

1.算法封装和互相替换

2.运行时动态切换

3.在 Callback 类中的体现

 


 

 

先看这样一个头文件callback.h

#ifndef CALLBACK_H
#define CALLBACK_H// class PalmObject;
// class FaceObject;
// class PoseObject;
class Callback
{
public:Callback();virtual ~Callback();// 发送关键点检测结果(如人脸、手势的关键点坐标)virtual void sendLandmarkToLocal(long frameID, const char* data, int len) = 0;// 发送目标人脸检测/识别结果virtual void sendTargetFace(const char * result, int len) = 0;	// 错误回调,当处理过程中发生错误时调用virtual void onError(int error) = 0;// void sendDebugHandsData(PalmObject* obj, int w, int h, bool isLeft);// void sendDebugFaceData(FaceObject* obj, int w, int h);// void sendDebugPoseData(PoseObject* obj, int w, int h);// 通知处理超时void sendMsgForHandleTooLong(uint64_t dura_frame, uint64_t dura_pose, uint64_t dura_face,uint64_t dura_hand, uint64_t dura_eulur);// 发送性能统计信息(帧率、处理时间等)void sendMsgForStatics(uint64_t avm_handle_frame_time, uint64_t avm_handle_pose_time,uint64_t avm_handle_face_time, uint64_t avm_handle_hand_time,uint64_t avm_handle_eulur_time, int input_frame_num,int detect_pose_fps, int detect_face_fps,int detect_hand_fps, int detect_hand_left_fps,int detect_hand_right_fps, int detect_hand_two_fps,int eulur_holistic_fps);// 发送人脸特征数据void sendTargetFaceFeature(const char * result, int len);// 发送完整的推理结果(关键点+特征)void sendInferceHolisticData(long frameID, long frame_duration, long ai_duration,const char* holistic_landmark_data, int len,const char* featureData, int featureDataLen);// 发送后处理数据void sendPostProcessData(uint64_t frameID, int dura,const char* holistic_data, int holistic_len);private:uint64_t m_uuid;
};
#endif

        我们可以发现这个C++类是一个抽象基类,主要用于定义回调接口,实现异步通信和事件通知机制,它在典型的数据处理流水线(如计算机视觉、AI推理应用)中扮演着关键角色。

        这个类是一个典型的例子,主要作用是为底层算法、处理模块提供一个统一的接口,使其能够向上层应用(如UI、业务逻辑层)发送处理结果、错误信息和性能数据,而无需关心上层如何具体实现这些功能。

        同时在这个类中体现了两种重要的设计模式:策略模式和观察者模式,借助这个类来理解下这两个比较常见的设计模式。

 

观察者模式

        核心思想:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

以Callback类为例:

主题(被观察者)- 处理引擎


class ProcessingEngine {
private:Callback* observer;  // 观察者public:void setObserver(Callback* cb) {this->observer = cb;}void processFrame(const Frame& frame) {try {// 处理帧数据...auto landmarks = detectLandmarks(frame);// 通知观察者(回调)if (observer) {observer->sendLandmarkToLocal(frame.id, landmarks.data(), landmarks.size());}} catch (const exception& e) {// 发生错误时通知观察者if (observer) {observer->onError(ERROR_CODE);}}}
};

观察者实现


class MyApp : public Callback {
private:ProcessingEngine engine;public:MyApp() {engine.setObserver(this);  // 注册为观察者}// 当被观察者状态变化时被调用void sendLandmarkToLocal(long frameID, const char* data, int len) override {updateUIWithLandmarks(data, len);}void onError(int error) override {showErrorMessage(error);}
};

        这种设计模式的好处在于,处理引擎不需要知道谁在接收结果,当状态变化立即通知所有观察者,并且可以动态添加或者移除观察者。

 

策略模式

        核心思想定义一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。

先举一个好理解的例子:

 1.算法封装和互相替换

        想象有一个导航应用,它提供不同的路线规划策略最快路线算法,最短路线算法,避开收费算法。

        这些不同的算法就是不同的"策略",它们可以在运行时根据用户选择动态切换,而不需要修改导航应用的核心代码。

        代码示例:

1.定义策略接口:

// 策略接口 - 定义算法的共同契约
class RouteStrategy {
public:virtual ~RouteStrategy() {}virtual void calculateRoute(const Point& start, const Point& end) = 0;
};

2.实现具体的策略算法

// 具体策略1: 最快路线算法
class FastestRoute : public RouteStrategy {
public:void calculateRoute(const Point& start, const Point& end) override {cout << "Calculating fastest route from " << start << " to " << end << endl;// 实现最快路线的具体算法}
};// 具体策略2: 最短路线算法  
class ShortestRoute : public RouteStrategy {
public:void calculateRoute(const Point& start, const Point& end) override {cout << "Calculating shortest route from " << start << " to " << end << endl;// 实现最短距离的具体算法}
};// 具体策略3: 避开收费算法
class AvoidTollsRoute : public RouteStrategy {
public:void calculateRoute(const Point& start, const Point& end) override {cout << "Calculating toll-free route from " << start << " to " << end << endl;// 实现避开收费站的具体算法}
};

3.上下文类--使用策略

class NavigationApp {
private:RouteStrategy* strategy;  // 持有策略对象的指针public:// 设置策略 - 这就是动态切换的关键!void setStrategy(RouteStrategy* newStrategy) {strategy = newStrategy;}void navigate(const Point& start, const Point& end) {if (strategy) {strategy->calculateRoute(start, end);  // 委托给当前策略执行}}
};

2.运行时动态切换

int main() {NavigationApp app;Point start("北京"), end("上海");// 场景1: 用户想要最快路线FastestRoute fastest;app.setStrategy(&fastest);  // 动态设置为最快路线策略app.navigate(start, end);   // 输出: Calculating fastest route...// 场景2: 用户改变主意,想要避开收费AvoidTollsRoute noTolls; app.setStrategy(&noTolls);  // 动态切换为避开收费策略app.navigate(start, end);   // 输出: Calculating toll-free route...// 场景3: 途中用户又想走最短距离ShortestRoute shortest;app.setStrategy(&shortest); // 再次动态切换app.navigate(start, end);   // 输出: Calculating shortest route...return 0;
}

3.在 Callback 类中的体现

        回到最初的Callback类,策略模式的应用:

// 策略接口定义
class Callback {
public:virtual void sendLandmarkToLocal(long frameID, const char* data, int len) = 0;virtual void sendTargetFace(const char* result, int len) = 0;	virtual void onError(int error) = 0;// ... 其他方法
};// 不同的处理策略
class RealTimeDisplay : public Callback {void sendLandmarkToLocal(...) override {// 策略1: 实时UI显示updateDisplay(data, len);}
};class DataLogger : public Callback {void sendLandmarkToLocal(...) override {// 策略2: 数据记录和分析logForAnalysis(frameID, data, len);}
};class NetworkForwarder : public Callback {void sendLandmarkToLocal(...) override {// 策略3: 网络传输sendToCloud(data, len);}
};// 运行时动态切换
ProcessingEngine engine;
RealTimeDisplay displayStrategy;
DataLogger loggingStrategy;// 根据应用模式动态切换回调策略
if (isDebugMode) {engine.setCallback(&loggingStrategy);
} else {engine.setCallback(&displayStrategy); 
}// 甚至可以在运行时根据用户操作切换
userButton.onClick([&]() {engine.setCallback(&networkStrategy);  // 动态切换!
});

 

        每个算法被封装在独立的类中,这些类实现相同的接口,因此可以互相替换,替换发生在运行时,也不需要重新编译代码,而且可以根据配置、用户输入、系统状态等动态选择算法,这种设计方式让系统变得极其灵活和可维护。

        

        在这个Callback类中,两种模式完美结合:观察者模式确保当数据处理完成时及时通知上层,策略模式让上层可以自由决定如何处理接收到的数据。

        两种设计模式的区别在于策略模式核心关注的是如何做(算法的选择与替换),观察者模式则关注的是何时做(状态变化的通知机制)。

 

 

http://www.dtcms.com/a/342288.html

相关文章:

  • 小红书AI落地与前端开发技术全解析(From AI)
  • Python 正则表达式(更长的正则表达式示例)
  • 【基础排序】CF - 赌场游戏Playing in a Casino
  • 机器学习4
  • 精算中的提升曲线(Lift Curve)与机器学习中的差别
  • 网络打印机安装操作指南
  • 健康常识查询系统|基于java和小程序的健康常识查询系统设计与实现(源码+数据库+文档)
  • CentOS7安装部署PostgreSQL
  • 《PostgreSQL内核学习:slot_deform_heap_tuple 的分支消除与特化路径优化》
  • ES_文档
  • 2025-08-21 Python进阶6——迭代器生成器与with
  • Python项目开发- 动态设置工作目录与模块搜索路径
  • strerror和perror函数的使用及其联系和区别
  • 43-Python基础语法-3
  • QWidget/QMainWindow与QLayout的布局
  • CSDN使用技巧
  • Pandas中数据分组进阶以及数据透视表
  • 链表-143.重排链表-力扣(LeetCode)
  • 微信小程序集成vant-weapp时,构建npm报错的解决办法
  • 基于springboot的中医养生管理系统
  • Pytorch基础学习--张量(生成,索引,变形)
  • 火语言 RPA 进阶功能:让自动化更实用​
  • 交易高光时刻-01
  • SOP到自动化:一种适合小型金融机构的轻量级开源工具整合方案
  • Vue3+Spring Boot技术栈,前端提交混合表单数据(普通字段+文件字段),上传文件,后端插入数据,将文件保存到数据库
  • Docker端口映射与数据卷完全指南
  • 几张PPT快速了解云原生与华为云CCE方案
  • Eureka和Nacos的原理分析
  • openEuler系统中r如何将docker安装在指定目录
  • CentOS 7常用国内源配置:阿里云、腾讯云、华为云、清华源