C语言-访问者模式详解与实践

C语言访问者模式详解与实践 - 传感器数据处理系统

1. 什么是访问者模式?

在嵌入式系统中,我们经常需要对不同传感器的数据进行多种处理,如数据校准、过滤、存储等。访问者模式允许我们在不修改传感器代码的情况下,添加新的数据处理方法。

2. 为什么需要访问者模式?

  • 分离数据采集和处理逻辑
  • 便于添加新的数据处理方法
  • 避免修改现有传感器代码
  • 便于数据处理的复用
  • 结构清晰,易于维护

3. 实际应用场景

  • 多传感器数据处理
  • 数据校准和滤波
  • 传感器状态监控
  • 数据记录和分析
  • 故障诊断系统

4. 代码实现

4.1 头文件 (sensor_visitor.h)

#ifndef SENSOR_VISITOR_H
#define SENSOR_VISITOR_H#include <stdint.h>// 传感器类型
typedef enum {TEMP_SENSOR,HUMIDITY_SENSOR
} SensorType;// 传感器数据结构
typedef struct {uint16_t raw_data;    // 原始数据uint32_t timestamp;   // 时间戳SensorType type;      // 传感器类型
} SensorData;// 温度传感器
typedef struct {SensorData data;float offset;         // 温度补偿值
} TempSensor;// 湿度传感器
typedef struct {SensorData data;uint8_t threshold;    // 湿度阈值
} HumiditySensor;// 访问者接口
typedef struct {void (*visit_temp)(void* self, TempSensor* sensor);void (*visit_humidity)(void* self, HumiditySensor* sensor);void* context;        // 访问者上下文
} SensorVisitor;// 传感器操作接口
void accept_visitor(void* sensor, SensorType type, SensorVisitor* visitor);// 创建传感器
TempSensor* create_temp_sensor(uint16_t raw_data, float offset);
HumiditySensor* create_humidity_sensor(uint16_t raw_data, uint8_t threshold);// 创建访问者
SensorVisitor* create_calibration_visitor(void);   // 校准访问者
SensorVisitor* create_filter_visitor(void);        // 滤波访问者
SensorVisitor* create_alarm_visitor(void);         // 报警访问者// 销毁函数
void destroy_sensor(void* sensor);
void destroy_visitor(SensorVisitor* visitor);#endif // SENSOR_VISITOR_H

4.2 实现文件 (sensor_visitor.c)

#include "sensor_visitor.h"
#include <stdio.h>
#include <stdlib.h>// 传感器创建函数
TempSensor* create_temp_sensor(uint16_t raw_data, float offset) {TempSensor* sensor = (TempSensor*)malloc(sizeof(TempSensor));sensor->data.raw_data = raw_data;sensor->data.timestamp = 0;  // 实际应用中需要获取真实时间戳sensor->data.type = TEMP_SENSOR;sensor->offset = offset;return sensor;
}HumiditySensor* create_humidity_sensor(uint16_t raw_data, uint8_t threshold) {HumiditySensor* sensor = (HumiditySensor*)malloc(sizeof(HumiditySensor));sensor->data.raw_data = raw_data;sensor->data.timestamp = 0;sensor->data.type = HUMIDITY_SENSOR;sensor->threshold = threshold;return sensor;
}// 校准访问者实现
static void calibrate_temp(void* self, TempSensor* sensor) {float real_temp = sensor->data.raw_data * 0.1f + sensor->offset;printf("温度校准: %.1f°C (原始值: %d, 偏移: %.1f)\n", real_temp, sensor->data.raw_data, sensor->offset);
}static void calibrate_humidity(void* self, HumiditySensor* sensor) {float real_humidity = sensor->data.raw_data * 0.1f;printf("湿度校准: %.1f%% (原始值: %d)\n", real_humidity, sensor->data.raw_data);
}// 滤波访问者实现
static void filter_temp(void* self, TempSensor* sensor) {// 简单的阈值滤波if (sensor->data.raw_data > 1000) {printf("温度数据滤波: 数值异常\n");} else {printf("温度数据滤波: 数值正常\n");}
}static void filter_humidity(void* self, HumiditySensor* sensor) {if (sensor->data.raw_data > 1000) {printf("湿度数据滤波: 数值异常\n");} else {printf("湿度数据滤波: 数值正常\n");}
}// 报警访问者实现
static void alarm_temp(void* self, TempSensor* sensor) {float real_temp = sensor->data.raw_data * 0.1f + sensor->offset;if (real_temp > 50.0f) {printf("温度报警: 温度过高 (%.1f°C)\n", real_temp);}
}static void alarm_humidity(void* self, HumiditySensor* sensor) {if (sensor->data.raw_data > sensor->threshold) {printf("湿度报警: 超过阈值 %d\n", sensor->threshold);}
}// 创建访问者
SensorVisitor* create_calibration_visitor(void) {SensorVisitor* visitor = (SensorVisitor*)malloc(sizeof(SensorVisitor));visitor->visit_temp = calibrate_temp;visitor->visit_humidity = calibrate_humidity;return visitor;
}SensorVisitor* create_filter_visitor(void) {SensorVisitor* visitor = (SensorVisitor*)malloc(sizeof(SensorVisitor));visitor->visit_temp = filter_temp;visitor->visit_humidity = filter_humidity;return visitor;
}SensorVisitor* create_alarm_visitor(void) {SensorVisitor* visitor = (SensorVisitor*)malloc(sizeof(SensorVisitor));visitor->visit_temp = alarm_temp;visitor->visit_humidity = alarm_humidity;return visitor;
}// accept函数实现
void accept_visitor(void* sensor, SensorType type, SensorVisitor* visitor) {switch (type) {case TEMP_SENSOR:visitor->visit_temp(visitor, (TempSensor*)sensor);break;case HUMIDITY_SENSOR:visitor->visit_humidity(visitor, (HumiditySensor*)sensor);break;}
}// 销毁函数
void destroy_sensor(void* sensor) {free(sensor);
}void destroy_visitor(SensorVisitor* visitor) {free(visitor);
}

4.3 使用示例 (main.c)

#include "sensor_visitor.h"
#include <stdio.h>int main() {// 创建传感器TempSensor* temp_sensor = create_temp_sensor(250, -2.5f);  // 25.0°C, -2.5偏移HumiditySensor* humidity_sensor = create_humidity_sensor(650, 800);  // 65.0%, 阈值80%// 创建访问者SensorVisitor* calibration = create_calibration_visitor();SensorVisitor* filter = create_filter_visitor();SensorVisitor* alarm = create_alarm_visitor();// 处理温度传感器数据printf("=== 温度传感器处理 ===\n");accept_visitor(temp_sensor, TEMP_SENSOR, calibration);accept_visitor(temp_sensor, TEMP_SENSOR, filter);accept_visitor(temp_sensor, TEMP_SENSOR, alarm);// 处理湿度传感器数据printf("\n=== 湿度传感器处理 ===\n");accept_visitor(humidity_sensor, HUMIDITY_SENSOR, calibration);accept_visitor(humidity_sensor, HUMIDITY_SENSOR, filter);accept_visitor(humidity_sensor, HUMIDITY_SENSOR, alarm);// 清理资源destroy_sensor(temp_sensor);destroy_sensor(humidity_sensor);destroy_visitor(calibration);destroy_visitor(filter);destroy_visitor(alarm);return 0;
}

5. 代码分析

5.1 关键设计点

  1. 传感器数据结构清晰
  2. 处理逻辑分离
  3. 易于扩展新的处理方法
  4. 资源管理完善

5.2 实现特点

  1. 适合嵌入式系统
  2. 代码简洁高效
  3. 内存占用小
  4. 处理流程清晰

6. 编译和运行

gcc -c sensor_visitor.c -o sensor_visitor.o
gcc -c main.c -o main.o
gcc sensor_visitor.o main.o -o sensor_demo

7. 注意事项

  1. 内存使用要谨慎
  2. 避免过度设计
  3. 考虑实时性要求
  4. 错误处理要完善

8. 改进建议

  1. 添加数据存储功能
  2. 实现数据平滑处理
  3. 添加更多传感器类型
  4. 支持批量数据处理

9. 总结

这个例子展示了访问者模式在嵌入式系统中的实际应用。通过将传感器数据采集和处理逻辑分离,我们可以灵活地添加新的数据处理方法,同时保持代码的清晰和可维护性。

参考资料

  1. 《嵌入式系统设计》
  2. 《C语言程序设计》
  3. 《传感器技术手册》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(UI自动化测试web端)第二篇:元素定位的方法_xpath路径定位

1、第一种xpath路径定位&#xff1a; 绝对路径&#xff1a;表达式是以 /html开头&#xff0c;元素的层级之间是以 / 分隔相同层级的元素可以使用下标&#xff0c;下标是从1开始的需要列出元素所经过的所有层级元素&#xff0c;工作当中一般不使用绝对路径 例&#xff1a;/html/…

设置GeoJSONVectorTileLayer中的line填充图片

设置GeoJSONVectorTileLayer中的line填充图片 关键&#xff1a;linePatternFile const style [{filter: true,renderPlugin: {dataConfig: {type: "line",},type: "line",},symbol: {linePatternFile: "http://examples.maptalks.com/resources/pat…

electron框架(4.0)electron-builde和electron Forge的打包方式

----使用electron-builder打包&#xff08;需要魔法&#xff09; --安装electron-builder: npm install electron-builder -D--package.json中进行相关配置&#xff1a; {"name": "video-tools","version": "1.0.0","main&quo…

让 MGR 不从 Primary 的节点克隆数据?

问题 MGR 中&#xff0c;新节点在加入时&#xff0c;为了与组内其它节点的数据保持一致&#xff0c;它会首先经历一个分布式恢复阶段。在这个阶段&#xff0c;新节点会随机选择组内一个节点&#xff08;Donor&#xff09;来同步差异数据。 在 MySQL 8.0.17 之前&#xff0c;同…

第三十二篇 深入解析Kimball维度建模:构建企业级数据仓库的完整框架

目录 一、维度建模设计原则深度剖析1.1 业务过程驱动设计1.2 星型模式VS雪花模式 二、维度建模五步法实战&#xff08;附完整案例&#xff09;2.1 业务需求映射2.2 模型详细设计2.3 缓慢变化维处理 三、高级建模技术解析3.1 渐变维度桥接表3.2 快照事实表设计 四、性能优化体系…

IntelliJ IDEA 中 Maven 的 `pom.xml` 变灰带横线?一文详解解决方法

前言 在使用 IntelliJ IDEA 进行 Java 开发时&#xff0c;如果你发现项目的 pom.xml 文件突然变成灰色并带有删除线&#xff0c;这可能是 Maven 的配置或项目结构出现了问题。 一、问题现象与原因分析 现象描述 文件变灰&#xff1a;pom.xml 在项目资源管理器中显示为灰色。…

缓存过期时间之逻辑过期

1. 物理不过期&#xff08;Physical Non-Expiration&#xff09; 定义&#xff1a;在Redis中不设置EXPIRE时间&#xff0c;缓存键永久存在&#xff08;除非主动删除或内存淘汰&#xff09;。目的&#xff1a;彻底规避因缓存自动过期导致的击穿&#xff08;单热点失效&#xff…

基于WebAssembly的浏览器密码套件

目录 一、前言二、WebAssembly与浏览器密码套件2.1 WebAssembly技术概述2.2 浏览器密码套件的需求三、系统设计思路与架构3.1 核心模块3.2 系统整体架构图四、核心数学公式与算法证明4.1 AES-GCM加解密公式4.2 SHA-256哈希函数五、异步任务调度与GPU加速设计5.1 异步任务调度5.…

Qt的内存管理机制

在Qt中&#xff0c;显式使用new创建的对象通常不需要显式调用delete来释放内存&#xff0c;这是因为Qt提供了一种基于对象树(Object Tree)和父子关系(Parent-Child Relationship)的内存管理机制。这种机制可以自动管理对象的生命周期&#xff0c;确保在适当的时候释放内存&…

数据结构之双向链表-初始化链表-头插法-遍历链表-获取尾部结点-尾插法-指定位置插入-删除节点-释放链表——完整代码

数据结构之双向链表-初始化链表-头插法-遍历链表-获取尾部结点-尾插法-指定位置插入-删除节点-释放链表——完整代码 #include <stdio.h> #include <stdlib.h>typedef int ElemType;typedef struct node{ElemType data;struct node *next, *prev; }Node;//初化链表…

【Linux网络-五种IO模型与阻塞IO】

一、引入 网络通信的本质就是进程间的通信&#xff0c;进程间通信的本质就是IO&#xff08;Input&#xff0c;Output&#xff09; I/O&#xff08;input/output&#xff09;也就是输入和输出&#xff0c;在冯诺依曼体系结构当中&#xff0c;将数据从输入设备拷贝到内存就叫作…

算法-最大公约数

1、约数&#xff1a; 1.1 试除法求约数 原理&#xff1a;只需要遍历最小的约数即可&#xff0c;较大的那个可以直接算出来。 import java.util.*; public class Main {static Scanner sc new Scanner(System.in);public static void main(String[] args) {int t sc.nextIn…

湖北楚大夫

品牌出海已成为众多企业拓展业务、提升竞争力的关键战略。楚大夫(chudafu.com)作为一家专注于品牌出海、海外网络营销推广以及外贸独立站搭建的公司&#xff0c;凭借其专业、高效、创新的服务模式&#xff0c;致力于成为中国企业走向国际市场的坚实后盾与得力伙伴。楚大夫通过综…

Flutter 学习之旅 之 flutter 使用 connectivity_plus 进行网路状态监听(断网/网络恢复事件监听)

Flutter 学习之旅 之 flutter 使用 connectivity_plus 进行网路状态监听&#xff08;断网/网络恢复事件监听&#xff09; 目录 Flutter 学习之旅 之 flutter 使用 connectivity_plus 进行网路状态监听&#xff08;断网/网络恢复事件监听&#xff09; 一、简单介绍 二、conne…

从零开始实现 C++ TinyWebServer 处理请求 HttpRequest类详解

文章目录 HTTP 请求报文HttpRequest 类实现 Init() 函数实现 ParseRequestLine() 函数实现 ParseHeader() 函数实现 ParsePath() 函数实现 ParseBody() 函数实现 ParsePost() 函数实现 ParseFromUrlEncoded() 函数实现 UserVerify() 函数实现 Parse() 函数HttpRequest 代码Http…

systemd-networkd 的 *.network 配置文件详解 笔记250323

systemd-networkd 的 *.network 配置文件详解 笔记250323 查看官方文档可以用 man systemd.network命令, 或访问: https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html 名称 systemd.network — 网络配置 概要 network.network 描述 一个纯…

自定义mavlink 生成wireshark wlua插件错误(已解决)

进入正题 python3 -m pymavlink.tools.mavgen --langWLua --wire-protocol2.0 --outputoutput/develop message_definitions/v1.0/development.xml 编译WLUA的时候遇到一些问题 1.ERROR:SCHEMASV:SCHEMAV_CVC_ENUMERATION_VALID 3765:0:ERROR:SCHEMASV:SCHEMAV_CVC_ENUMERAT…

计算机操作系统(四) 操作系统的结构与系统调用

计算机操作系统&#xff08;四&#xff09; 操作系统的结构与系统调用 前言一、操作系统的结构1.1 简单结构1.2 模块化结构1.3 分层化结构1.4 微内核结构1.5 外核结构 二、系统调用1.1 系统调用的基本概念1.2 系统调用的类型 总结&#xff08;核心概念速记&#xff09;&#xf…

深入解析 Spring IOC AOP:原理、源码与实战

深入解析 Spring IOC & AOP&#xff1a;原理、源码与实战 Spring 框架的核心在于 IOC&#xff08;控制反转&#xff09; 和 AOP&#xff08;面向切面编程&#xff09;。今天&#xff0c;我们将深入剖析它们的原理&#xff0c;结合源码解析&#xff0c;并通过 Java 代码实战…

LLM之RAG理论(十四)| RAG 最佳实践

RAG 的过程很复杂&#xff0c;包含许多组成部分。我们如何确定现有的 RAG 方法及其最佳组合&#xff0c;以确定最佳 RAG 实践&#xff1f; 论文 《Searching for Best Practices in Retrieval-Augmented Generation》给出了回答。 本文将从以下三方面进行介绍&#xff1a; 首先…