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

目录

观察者模式

策略模式

1.算法封装和互相替换

2.运行时动态切换

[3.在 Callback 类中的体现](#3.在 Callback 类中的体现)


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

cpp 复制代码
#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类为例:

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

cpp 复制代码
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);
            }
        }
    }
};

观察者实现

cpp 复制代码
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.定义策略接口:

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

2.实现具体的策略算法

cpp 复制代码
// 具体策略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.上下文类--使用策略

cpp 复制代码
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.运行时动态切换

cpp 复制代码
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类,策略模式的应用:

cpp 复制代码
// 策略接口定义
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类中,两种模式完美结合:观察者模式 确保当数据处理完成时及时通知上层,策略模式让上层可以自由决定如何处理接收到的数据。

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

相关推荐
牛角上的男孩2 小时前
apt update Ign and 404 Not Found
开发语言·数据库
yzzzzzzzzzzzzzzzzz3 小时前
JavaScript 操作 DOM
开发语言·javascript·ecmascript
海绵宝宝汉堡包4 小时前
c# 项目 文件夹
开发语言·c#
时间之里5 小时前
c++:MFC中sqlite3的使用(附实际案例)
c++·mfc·sqlite3
小马学嵌入式~5 小时前
数据结构:队列 二叉树
c语言·开发语言·数据结构·算法
Slaughter信仰6 小时前
深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第二章知识点问答(21题)
java·开发语言·jvm
John_ToDebug7 小时前
Chrome 内置扩展 vs WebUI:浏览器内核开发中的选择与实践
前端·c++·chrome
焊锡与代码齐飞7 小时前
嵌入式第三十五课!!Linux下的网络编程
linux·运维·服务器·开发语言·网络·学习·算法
KeithTsui8 小时前
GCC C语言整数转换的理解(Understanding of Integer Conversions in C with GCC)
c语言·开发语言·算法