使用模板方法模式封装协议消息

news2024/12/22 23:34:23

目录

整体框架

模板方法介绍

关于本案例设计

c++ impl惯用法

c++impl惯用法好处

此案例impl惯用法的设计

关于序列化和反序列化

序列化和反序列化

本项目使用介绍

谷歌测试

谷歌测试环境

谷歌测试用例

完整源码地址


概述

本文介绍了从

  • 设计模式之模板方法模式
  • 协议消息设计之序列化和反序列化
  • 谷歌单元测试
  • c++ impl惯用法,用于接口设计,隐藏设计细节,只暴露接口

整体框架

模板方法介绍

        模板方法模式是设计模式中比较常用的一种,此模式就是提供了一个很好的代码复用平台,意在将不变的行为放到基类,去除子类中的重复代码。当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现,模板方法模式把这些行为搬移到单一的地方,这样就可以帮助子类拜托重复不变的行为的纠缠。

        由于类图太简单,就不单独画出,就一个基类和n个派生类,main函数中多态起对象(类似简单工厂模式),通过基类对象调用基类的固定方法,通过基类的固定方法调用虚函数实现多态的效果。

关于本案例设计

        本案例重点实现IMessage基类,和衍生出来的各个消息子类,由于每个消息的数据结构不同,导致序列化反序列化的方法不同,但是头部数据的序列化反序列化方法是相同的,而且尽管方法不同,但是步骤都是一致的,因此套用模板方法模式。

        下面是基类的实现方法serialize和deserialize实现了对外接口序列化和反序列化,内部再通过多态,调用到各个子类的serializeContent和deserializeContent这两个实际的接口。

        整个项目结构如下,一个IMessage基类,实现了两个子类消息都继承于IMessage类,types.h中放置所有消息的结构体。

c++ impl惯用法

c++impl惯用法好处

        《c++服务器开发精髓》——张远龙书中得知此方法,网上也有很多demo,此设计多用于接口类的编写,由于不想对外暴露太多的内部实现方法和成员变量,将内部方法和变量写入一个内部类中,对外只暴露一个此内部类的指针或者智能指针。

此案例impl惯用法的设计

        此案例的这个思想主要体现在IMessage类中,设想我们是设计此类的第三方公司,此类给到客户是只写给出客户用得到的接口不想给客户知道我们使用那些内部方法和变量,可以像如下设计在message.h头文件中写入一个不可拷贝只能指针,指向IMessageImpl这个类,当然,使用之前先声明一下。

         之后在message.cpp中定义这个IMessageImpl内部类,使用IMessage::IMessageImpl类似继承的方法表面是内部类,定义MsgHead私有变量,serializeHeader、deserializeHeader私有方法,分别用来存储消息的头部内容,和实现对消息的头部内容的序列化和反序列化。

        在IMessage类构造时IMessage::IMessage(): m_pImpl(make_unique<IMessageImpl>())将暴露在外的m_pImpl只能指针实例化,在IMessage中能直接使用m_pImpl->msgHead变量或m_pImpl->deserializeHeader方法,隐藏了内部实现。

关于序列化和反序列化

序列化和反序列化

        程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这些过程将会涉及到程序数据转化成能被存储并传输的格式,因此被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)
        简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻松地存储和传输数据。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。

  • 序列化:将对象变成字节流的形式传出去。
  • 反序列化:从字节流恢复成原来的对象。

成熟的案例:Google Protocol Buffers(protobuf)

本项目使用介绍

        本案例将序列化和反序列化实现在types.h头文件中,分别实现了以下几种类型的序列化和反序列化:(给出普通类型和string类型的实现方法)

  • 普通类型 <> 字节流

  • string类型 <> 字节流

  • vector类型 <> 字节流
  • vector of strings <> 字节流  (多个string)
  • vector of vectors <> 字节流     (多个数组)        

谷歌测试

谷歌测试环境

        接触过单元测试的同学应该都了解谷歌测试,这里就简单说一下怎么Qt集成谷歌测试的一种方法吧。首先需要先有谷歌测试的库文件和头文件(此处没有的同学可以上我的git里面取),当然也有另一种方法直接集成googletest的源码的我这里就不说了大家网上自己找下吧,我也没实践过。下面是谷歌测试的依赖目录:

         我这边使用的是cmake,因此需要在CMakeLists.txt中加入以下库和头问价的引用,windows下包括目录的引用和库文件夹的引用,库文件的引用也可以在main函数中用 #pragma comment(lib, "../mypro2buf/gtest/lib/gtest.lib") 代替,此处我们还是使用target_link_libraries,第二种方法需要知道执行文件目录,或者写库的绝对路径,每个人不统一。

        linux下先使用软件源下载google test的dev包,之后同样使用target_link_libraries引用gtest(linux软件安装之后会到默认添加过环境变量的目录则不需要指定库和头文件目录),注意linux下需要添加一个pthread库。

        最后在main函数中 #include "gtest/gtest.h" 环境就搭建好了

谷歌测试用例

        此处测试两个消息,序列化和反序列化之后的内容是否一致,main函数和测试用例试下如下

         此处详解一个消息的过程,消息名称是MessageLoginRequest::IMessage,实现了登录消息,此消息包含的数据是两个string类型。一个是用户名一个是密码,通过MessageLoginRequest对象调用基类的serialize方法,将序列化之后的字节流buff存在msgBuf中,实际情况下,这个msgBuf会通过网络或者其他底层传输协议传输到对端,对端收到buff之后实现deserialize,当然,对端会通过头部信息获取此消息的种类。

        此处本地模拟对端直接收到了msgBuf,直接创建loginRequest2来反序列化这个buff,反序列化之后会将解出来的用户名和密码存在loginRequest2中,此处使用谷歌测试对原始值和loginRequest2中的值对比测试是否相等,相等则表面序列化和反序列化成功。

EXPECT_EQ(data.username,  loginRequest2.getLogin().username);   EXPECT_EQ(data.password,  loginRequest2.getLogin().password);

谷歌测试还有判断是否为真,和其他类型变量的测试方法类似EXPECT_EQ,大家可以在网上搜索做一些别的字段的测试。这样我们的测试就结束了。

         测试结果:

         最后,欢迎大家一起学习c/c++,一起探讨和改进,一起进步。

完整源码地址

mypro2buf · gaotao/mytest-projects - 码云 - 开源中国 (gitee.com)

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

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

相关文章

面对CPU狂飙时的5步解决方案

现在企业对后端开发的要求越来越高&#xff0c;不仅要求我们会写代码&#xff0c;还要我们能够进行部署和运维&#xff01; 项目上线并运行一段时间后&#xff0c;可能会发现部署所在的Linux服务器CPU占用过高&#xff0c;该如何排查解决&#xff1f; 本文用5步带你搞定线上CPU…

操作系统-进程和线程-同步、互斥、死锁

目录 一、同步互斥 二、互斥的实现方法 2.1软件实现 2.1.1单标志法 2.1.2双标志先检查 2.1.3双标志后检查 2.1.4Petersons算法 2.2硬件实现 2.2.1 TestAndSet指令 2.2.2 Swap指令 三、信号量机制 3.1整形变量 3.2 记录型变量 3.3用信号量实现进程互斥、同步、前驱关系…

Sui与F1甲骨文红牛车队达成合作

在近期达成的一项为期多年的合作协议中&#xff0c;甲骨文红牛车队将利用Sui网络开发&#xff0c;为粉丝带来全新的数字化体验。 甲骨文红牛车队的粉丝将很快在Sui网络上体验到他们最爱的一级方程式车队带来的激情。最近几个赛季一直统治着F1赛场的甲骨文红牛车队&#xff0c;与…

代码随想录算法训练营第五十三天 | 力扣 1143.最长公共子序列, 1035.不相交的线, 53. 最大子序和

1143.最长公共子序列 题目 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符…

2022年值得关注的7个主要SD-WAN趋势

随着SD-WAN技术在2022年继续发展成熟&#xff0c;该技术在集成远程访问、自动化和多云连接方面的支持有望得到更多的改进。 软件定义WAN仍然是增强用户体验(UX)&#xff0c;提高安全性&#xff0c;以及提供与基于云计算的应用程序的连接的一项关键技术。 随着SD-WAN的成熟&…

java设计模式之:原型模式

在我们的生活中&#xff0c;有很多例子&#xff0c;都是用到了原型模式&#xff0c;例如&#xff1a;我们去配钥匙的时候&#xff0c;肯定先要有一个原配钥匙才可以去配钥匙&#xff1b;《西游记》中孙悟空可以用猴毛根据自己的形象&#xff0c;复制&#xff08;又称“克隆”或…

时间序列预测 | Matlab基于北方苍鹰算法优化随机森林(NGO-RF)与随机森林(RF)的时间序列预测对比

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于北方苍鹰算法优化随机森林(NGO-RF)与随机森林(RF)的时间序列预测对比 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %-----------…

【Apache-Flink零基础入门】「入门到精通系列」手把手+零基础带你玩转大数据流式处理引擎Flink(基础概念解析)

手把手零基础带你玩转大数据流式处理引擎Flink 前言介绍Apache Flink 的定义、架构及原理Flink应用服务Streams有限数据流和无限数据流的区别 StateTimeAPI Flink架构体系 Flink操作处理Flink 的应用场景Flink 的应用场景&#xff1a;Data Pipeline实时数仓搜索引擎推荐 Flink …

华为诺亚 VanillaNet

文章标题&#xff1a;《VanillaNet: the Power of Minimalism in Deep Learning》 文章地址&#xff1a;https://arxiv.org/abs/2305.12972 github地址&#xff1a;https://github.com/huawei-noah/VanillaNet 华为诺亚方舟实验室和悉尼大学&#xff0c;2023年5月代码刚开源的…

基于HAL库的STM32的单定时器的多路输入捕获测量脉冲频率(外部时钟实现)

目录 写在前面 一般的做法&#xff08;定时器单通道输入捕获) 以外部时钟的方式(高低频都适用) 测试效果 写在前面 STM32的定时器本身有输入捕获的功能。可选择双端捕获&#xff0c;上升沿捕获或者是下降沿捕获。对应捕获频率来说,连续捕获上升沿或下降沿的时间间隔就是其脉…

手把手教你F103工程文件的创建并且通过protesu仿真验证创建工程文件的正确性(低成本)

目录 一、新建工程文件夹 二、新建一个工程框架 三、添加文件 四、仿真验证 五、仿真调试中遇到的问题并解决 一、新建工程文件夹 新建工程文件夹分为 2 个步骤&#xff1a;1&#xff0c;新建工程文件夹&#xff1b;2&#xff0c;拷贝工程相关文件。 1.新建工程文件 首先…

【04】STM32·HAL库开发-MDK5使用技巧 |文本美化 | 代码编辑技巧 | 查找与替换技巧 | 编译问题定位 | 窗口视图初始化

目录 1.文本美化&#xff08;熟悉&#xff09;1.1编辑器设置1.2字体和颜色设置1.3用户关键字设置1.4代码提示&语法检测1.5global.prop文件妙用 2.代码编辑技巧&#xff08;熟悉&#xff09;2.1Tab键的妙用2.2快速定位函数或变量被定义的地方2.3快速注释&快速取消注释 3…

python面向对象操作2(速通版)

目录 一、私有和公有属性的定义和使用 1.公有属性定义和使用 2.私有属性 二、继承 1.应用 2.子类不能用父类的私有方法 3.子类初始化父类 4.子类重写和调用父类方法 5.多层继承 6.多层继承-初始化过程 7.多继承基本格式 8.多层多继承时的初始化问题 9.多继承初始化…

云原生Docker Cgroups资源控制操作

资源控制 Docker 通过 Cgroup 来控制容器使用的资源配额&#xff0c;包括 CPU、内存、磁盘三大方面&#xff0c; 基本覆盖了常见的资源配额和使用量控制。 Cgroup 是 ControlGroups 的缩写&#xff0c;是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如…

Node服务器-express框架

1 Express认识初体验 2 Express中间件使用 3 Express请求和响应 4 Express路由的使用 5 Express的错误处理 6 Express的源码解析 一、手动创建express的过程&#xff1a; 1、在项目文件的根目录创建package.json文件 npm init 2、下载express npm install express 3、基本…

kafka3

分区副本机制 kafka 从 0.8.0 版本开始引入了分区副本&#xff1b;引入了数据冗余 用CAP理论来说&#xff0c;就是通过副本及副本leader动态选举机制提高了kafka的 分区容错性和可用性 但从而也带来了数据一致性的巨大困难&#xff01; 6.6.2分区副本的数据一致性困难 kaf…

多模态学习

什么是多模态学习&#xff1f; 模态 模态是指一些表达或感知事物的方式&#xff0c;每一种信息的来源或者形式&#xff0c;都可以称为一种模态 视频图像文本音频 多模态 多模态即是从多个模态表达或感知事物 多模态学习 从多种模态的数据中学习并且提升自身的算法 多…

【k8s 系列】k8s 学习三,docker回顾,k8s 起航

k8s 逐渐已经作为一个程序员不得不学的技术&#xff0c;尤其是做云原生的兄弟们&#xff0c;若你会&#xff0c;那么还是挺难的 学习 k8s &#xff0c;实践尤为重要&#xff0c;如果身边有自己公司就是做云的&#xff0c;那么云服务器倒是不用担心&#xff0c;若不是&#xff…

IMX6ULL PHY 芯片驱动

前言 之前使用 IMX6ULL 开发板时遇到过 nfs 挂载不上的问题&#xff0c;当时是通过更换官方新版 kernel 解决的&#xff0c;参考《挂载 nfs 文件系统》。 今天&#xff0c;使用自己编译的 kernel 又遇到了该问题&#xff0c;第二次遇到了&#xff0c;该正面解决了。 NFS 挂载…

18JS09——作用域

作用域 一、作用域1、作用域 二、变量的作用域1、变量作用域的分类2、全局变量3、局部变量4、全局变量和局部变量区别 三、作用域链 目标&#xff1a; 1、作用域 2、变量的作用域 3、作用域链 一、作用域 1、作用域 通常来说&#xff0c;一段程序代码中所用到的名字并不总是有…