C语言设计模式——命令模式

                                 C语言设计模式——命令模式

 

好处:让代码清晰明了,容易添加和删除,易维护。

哪些地方会用到命令模式?(列出几个常见的例子)

1、按键处理,每个按键按下得到一个索引(指的就是命令),一个按键对应一个处理函数。按键处理命令模式

2、协议解析(串口,网口,CAN,等等);以串口为例简单说明一下,比如有如下协议:http类型解析(html,jpg,jpeg...)

帧头命令数据长度数据内容校验帧尾
1字节1字节2字节n字节2字节1字节

命令1:0x01 温度

命令2:0x02 湿度

命令3:0x03 光照强度

传统的实现方式如下:(伪代码)

static uint8_t parse(char *buffer, uint16_t length)
{uint8_t head = buffer[0];uint8_t cmd = buffer[1];uint16_t len = (buffer[2] << 8) | buffer[3];uint16_t crc = CRCCheck(buffer, length - 3);uint8_t tail = buffer[length - 1];if((head != xxx) && (tail != xxx) && (crc != ((buffer[length - 3]) << 8) | buffer[length - 2])){return 0;}switch(cmd){case 0x01:int temperatue = *(int *)&buffer[4];printf("temperatue = %d\n", temperatue);break;case 0x02:int humidity = *(int *)&buffer[4];printf("humidity = %d\n", humidity);break;case 0x03:int illumination= *(int *)&buffer[4];printf("illumination = %d\n", illumination);break;default:printf("parse error\n");break;}return 1;
}

通过这段伪代码可以看出代码结构的一些问题,如果要添加更多的命令,势必需要向switch case语句中加入更多的case语句。使得解析函数越来越臃肿。当然我们可以使用如下方式规避一些问题:(伪代码)

// 当心字节对齐的问题
typedef struct
{uint8_t head;uint8_t cmd;uint16_t length;uint8_t data[1];
} package_t;static int parse_temperature(char *buffer)
{int value = *(int *)buffer;printf("temperature = %d\n", value);
}
static int parse_humidity(char *buffer)
{int value = *(int *)buffer;printf("humidity = %d\n", value);
}static int parse_illumination(char *buffer)
{int value = *(int *)buffer;printf("illumination = %d\n", value);
}static uint8_t parse(char *buffer, uint16_t length)
{package_t *frame = (package_t *)buffer;uint16_t crc = CRCCheck(buffer, length - 3);uint8_t tail = buffer[length - 1];if((frame->head != xxx) && (tail != xxx) && (crc != (buffer[length - 3]) << 8 | buffer[length - 2])){return 0;}switch(frame->cmd){case 0x01:parse_temperature(frame->data);break;case 0x02:parse_humidity(frame->data);break;case 0x03:parse_illumination(frame->data);break;default:printf("parse error\n");}return 1;
}

相比于第一段代码,已经有了很大的改善,扩展性也得到了很大的提升。随着项目的进行,解析函数还是可能会越来越大。接下来就开始介绍命令模式。在命令模式里面,我们只需要维护一个命令列表就行了,而不需要关注解析函数本身。(伪代码)

// 当心字节对齐的问题
typedef struct
{uint8_t head;uint8_t cmd;uint16_t length;uint8_t data[1];
} package_t;static int parse_temperature(char *buffer)
{int value = *(int *)buffer;printf("temperature = %d\n", value);
}
static int parse_humidity(char *buffer)
{int value = *(int *)buffer;printf("humidity = %d\n", value);
}static int parse_illumination(char *buffer)
{int value = *(int *)buffer;printf("illumination = %d\n", value);
}typedef struct
{uint8_t cmd;void (* handle)(char *buffer);
} package_entry_t;static const package_entry_t package_items[] =
{{0x01, parse_temperature},{0x02, parse_humidity},{0x03, parse_illumination},{0xFF, NULL},
};static uint8_t parse(char *buffer, uint16_t length)
{package_t *frame = (package_t *)buffer;uint16_t crc = CRCCheck(buffer, length - 3);uint8_t tail = buffer[length - 1];const package_entry_t *entry;if((frame->head != xxx) && (tail != xxx) && (crc != (buffer[length - 3]) << 8 | buffer[length - 2])){return 0;}for(entry = package_items; entry->handle != NULL; ++entry){if(frame->cmd == entry->cmd){entry->handle(frame->data);break;}}return 1;
}

        我们可以看到,解析函数写好之后就不用动了,需要变化的只是一个表。这样写能让代码看起来干净整洁清晰,命令也可以使用宏定义或者枚举,看自己的喜好吧。一个命令对应一个处理函数,尽量使用此类方式去取代swicth case的方式,始终让代码保持整洁易扩展易维护的特性。

        上面使用了命令模式作用于串口协议,同样的方式可以适用于各种协议,网口协议的话,格式都不用改。如果是can协议的话,将can的id用作命令,就ok了。其他的,类似。

 

 

 

 

 

 

 

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

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

相关文章

什么是音色?

要问最近最火的节目是什么&#xff1f;《浪姐》绝对可以冲击C位。要问最近最火的剧是哪部&#xff1f;有全中国小学生最近都怕的张东升老师那部前三甲无疑。要问最近最火的歌是哪首&#xff1f;《Mojito》或许是唯一的答案。这首极具拉丁风格的歌让周董再一次回答了“谁是周杰伦…

hive 语句总结_Hive常用命令总结

本文只是总结一些在Hive中常用的命令&#xff0c;并且假设需要的目录或者数据已经存在。创建表&#xff0c;\t作为列的分隔符create table trade_detail (id bigint,income double,expenses double,time string) row formate delimited fields terminated by \t;create table u…

php的用户认证(有点难度 多看几遍吧)

采用PHP的用户认证如果你希望在每一个脚本的基础上实现口令保护功能&#xff0c;那么你可以联合使用header()函数和$PHP_AUTH_USER、$PHP_AUTH_PW全局变量来创造一个基本的认证方案。通常的、基于服务器的认证请求/响应回合很象下面这个样子&#xff1a;1.用户向一台Web服务器请…

爱了雷布斯

本来今天想写个NTP的文章&#xff0c;但是因为小米昨天的这个操作一直想夸一下&#xff0c;所以写写雷布斯&#xff0c;吹吹雷布斯。我是米粉&#xff0c;肯定是米粉&#xff0c;前段时间还有读者来问我&#xff0c;现在能不能入手小米的股票&#xff0c;这个我不敢给建议&…

python爬取企业电话_Python爬取天眼查企业数据

作者本机环境&#xff1a;系统-windows10编程语言-PythonPython版本-Python3.6.8解析工具-Xpath(解析工具不唯一&#xff0c;均可&#xff0c;这里只演示xpath)编写工具-Pycharm本内容使用Python语言进行编写&#xff0c;而Python也是编写爬虫比较好的一款编程语言&#xff0c;…

开发常用工具

开发常用工具 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。一、编辑器 1、Notepad&#xff1a;意外关闭此软件文件不会丢失&#xff1b; 2、PSPad&#xff1a;保持上一次编辑状态&#xff0c;这样在你下次打开编辑器的时候可以直接显示原来的文件。此…

oracle 12.2.0.1 搭建 active dataguard

os: centos 7.4 database&#xff1a;12.2.0.1 dbf 本次是以 oracle database 12.2.0.1 dbf 的形式部署的&#xff0c;后面会记录 rac asm 的形式。 任何时候都要说下三种模式&#xff1a; 最大保护&#xff1a;maximize protection 最高性能&#xff1a;maximize perform…

运行地址与加载地址估计大部分人没弄明白~

本文为【单片机步入嵌入式Linux】系列文章的第二篇&#xff0c;主要是跟大家讲解一下链接过程中几个地址的区分与理解~1 单片机存储分配在玩单片机(以stm32为例)的时候会有RAM空间和ROM空间&#xff0c;RAM空间主要是用于数据的访问&#xff0c;而ROM空间用于存放烧录的固件&am…

foxpro:将表写入excel

oleApp CREATEOBJECT("Excel.Application")oleapp.workbooks.addoleapp.visible.t.SELECT ls*写入表的标题oleapp.cells(1,10).value"这是我的表"*oleapp.cells(1,10).font.fontname"黑体"oleapp.cells(1,10).font.size24nfieldcountAFIELDS(al…

adb打开网页_android 使用指定浏览器打开网页

梳理下流程&#xff1a;枚举对应浏览器包名到数组中数组循环根据包名找到对应的LaunchIntent通过LaunchIntent找到对应的LaunchActivity的包名Intent通过设置activity的包名类名/*** 工具类*/public class CheckApkExist {private static String ucPkgName "com.uc.brows…

博客目录列表(C与Linux部分)

一、C语言 1、C语言——关键字 2、C语言——位操作 3、C语言——数组、函数、指针 4、C语言——结构体 5、C语言——预编译 6、C语言——宏定义 7、C语言——字符串函数 8、C语言——可变参数 9、C语言——回调函数 10、数据结构——链表 11、数据结构——堆栈 12、数据结构——…

python-greenlet模块(协程)

12345678910111213141516from greenlet import greenletdef test1():print(12)gr2.switch()print(34)gr2.switch()def test2():print(56)gr1.switch()print(78)gr1 greenlet(test1)#启动一个协程gr2 greenlet(test2)#启动一个协程gr1.switch()#switch是协程切换高并发&#x…

我妈在深圳的这些日子

今天送了我丈母娘回家&#xff0c;平时在家里&#xff0c;我会叫妈。下面文章中写到的我爸、我妈、指的是我老丈人和丈母娘。上个周末&#xff0c;我跟我妈说&#xff0c;谢谢你过来帮忙我们照顾楠哥&#xff0c;辛苦你了。我说了两遍&#xff0c;可能她听的不是很清楚&#xf…

2010-04-25 搞定aftr

今天终于完全地把aftr给搞定了。 刚开始的时候&#xff0c;建了三台机器&#xff0c;甲&#xff0c;乙&#xff0c;丙&#xff0c;甲和乙通过ipv6相连&#xff0c;甲的ipv6地址为2001:0:0:1::2/64&#xff0c;乙的ipv6地址为2001:0:0:1::1/64&#xff0c;乙和丙通过ipv4相连&am…

linux下解包bin二进制文件_linux下如何使用docker二进制文件安装_docker离线安装

1,下载二进制文件https://download.docker.com/linux/static/stable/x86_64/docker-18.03.1-ce.tgz2,解压二进制文件tar xzvf docker-18.03.1-ce.tgz3,复制二进制文件到/usr/bin目录下cp docker/* /usr/bin/4,检查是否安装docker versionClient:Version: 18.03.1-ceAPI ve…

【腾讯面试题】兔子试毒

大家好&#xff0c;我是牛牛&#xff0c;经过了忙碌的一周&#xff0c;终于盼来了周五。今天给大家分享一道有趣有料的算法题&#xff0c;希望能让大家开启周末的好心情。01故事起源有1000瓶药水&#xff0c;其中有一瓶是毒药&#xff0c;只要喝上一滴&#xff0c;一天之后就必…

git clone 指定分支的内容

使用Git下载指定分支命令为&#xff1a;git clone -b 分支名仓库地址 使用Git下载v.2.8.1分支代码&#xff0c;使用命令&#xff1a;git clone -b v2.8.1 https://git.oschina.net/oschina/android-app.git转载于:https://www.cnblogs.com/pansidong/p/9284967.html

大型网站架构

一个小型的网站&#xff0c;比如个人网站&#xff0c;可以使用最简单的html静态页面就实现了&#xff0c;配合一些图片达到美化效果&#xff0c;所有的页面均存放在一个目录下&#xff0c;这样的网站对系统架构、性能的要求都很简单&#xff0c;随着互联网业务的不断丰富&#…

分享一个剪切板的小软件CopyQ

我是最近在工作的时候经常需要复制一些命令&#xff0c;而且这些命令如果用手敲的话会超级麻烦&#xff0c;所以体验了几个剪切板的小软件&#xff0c;这个是我体验之后觉得最不错的一个&#xff0c;分享给大家。软件链接地址https://github.com/hluk/CopyQ/releases软件图标我…

python2编码问题解决了吗_Python2编码问题

以下内容说的都是 python 2.x 版本简介基本概念Python “帮”你做的事情推荐姿势1、基本概念我们看到的输入输出都是‘字符’(characters)&#xff0c;计算机(程序)并不能直接处理&#xff0c;需要转化成字节数据(bytes)&#xff0c;因为程序只能处理 bytes 数据。例如&#xf…