学以致用C++设计模式 之 “适配器模式”

举报
看,未来 发表于 2020/12/30 01:22:00 2020/12/30
【摘要】 这个模式啊,怎么说呢,很多书里都说它是个补救模式,在设计的时候不要去考虑。 文章目录 出国旅游必备之“电源适配器”生火做饭舍它其谁的场景可用可不用的场景 出国旅游必备之“电源适配器” 见过电源适配器吗?电脑手机充电器就是“电源适配器”,但是我国的标准电压是220V,出了国可就不好乱插,别的国家的电压和我国不同。这时候就需要一个便携的电源变压器将...

这个模式啊,怎么说呢,很多书里都说它是个补救模式,在设计的时候不要去考虑。

在这里插入图片描述

出国旅游必备之“电源适配器”

见过电源适配器吗?电脑手机充电器就是“电源适配器”,但是我国的标准电压是220V,出了国可就不好乱插,别的国家的电压和我国不同。这时候就需要一个便携的电源变压器将国外电压转换成220V,这便是“适配器模式”的精髓:将你不能用的东西,在不破坏原物的前提下,通过中转变成你能用的东西。

生火做饭

上面呢,是对于“适配器模式”的标准理解,但是我有自己的理解。
我们的祖先呢,一开始是吃生的东西,后来有了火呢,他们就吃熟的东西了,那时候没那么多讲究,就是熟的好吃,所以吃熟的。看现在的人,也是可以吃生肉的,只是通过火的作用,会使得食物更加健康。
这个火,在我看来就是属于“适配器”,将本来可吃可不吃的生肉,变成了熟肉。我觉得吧,只要能使得项目某些小方面更加的便利,就可以采用适当的适配转换,不一定非要到了“别无他法”的时候才采用“适配器”。

舍它其谁的场景

来看个解压包模块的部分代码:

//Packetbase.h
#define MAX_PACKET_LENTH 1024
//设置包最大长度为1024,
// ! ! ! 暂时不考虑会太小的情况 ! ! !

typedef struct packet_header_st
{ int fd;//用于前后端通信即目标客户端fd(服务器用到) int funcId; // 功能号 //登录包0x01,注册包0x02,找回密码0x03,修改密码0x04 //客户端获取文件列表0x11,上传文件0x12,下载文件0x13,共享文件0x14, //新增目录0x15,删除目录0x16,删除文件0x17,文件移动0x18,目录移动0x19,文件重命名0x20,目录重命名0x22 //心跳0x21 //边缘服务器向中控服务器认证 0x30 int optid; // 操作码:请求0x00 和 应答0x01 int usrlenth;// 包体的长度 int packet_seq; //包序号 int packet_sum; //包总数 char to_fd[6]; //目标服务器名称 char dstAddr[6]; //预留 int syn; // 判断包头是否正确 0x04
}packet_header_t;

/************接入层数据包尾************/

typedef struct packet_tali_st//包尾,用来验证数据包的完整性
{ int pack_tail;//设置为0x05
}packet_tali_t;

/************数据包报文整体************/

typedef struct  packet_all_st
{ packet_header_t Head; char* body; packet_tali_st tail;
}packet_all_st;


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

上面的部分,是属于包头、包体、包尾的,属于解压包模块内聚部分,不对外开放。
接下来是实际拓展包:

//客户端登录请求包
typedef struct login
{ int id; int pwd; //密码
}Login_t;

//登录应答包
typedef struct res_login_st
{ int login_ret;  //登录结果: 1-登录成功,0-登录失败 int dir_id;  //初始文件列表id char reson[20]; //如果登录失败,返回失败原因,如果登录成功,返回初始目录名
}res_login_t;

//客户端注册请求包
typedef struct Register
{ int id; //账号 char tel[12];	//11位手机号 int pwd; //密码
}Register_t;

//注册应答包
typedef struct res_register_st
{ int register_ret;	//失败返回0,成功返回1 char reson[20];
}res_register_t;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

那么,要如何将不同的结构体塞进固定数据类型的包体 char* body; 呢?
使用适配器:

bool PacketCommand1::replyLogin(int state, int dir_id, char* reson, int fd) { int sz = sizeof(res_login_t); this->setBodySize(sz); this->Body = new char[sz]; Head.funcId = 0x01; Head.optid = 0x01; Head.fd = fd; Head.usrlenth = sz; Head.syn = 0x04; strcpy(Head.to_fd, "Front"); res_login_t* body = (res_login_t*)Body;		//适配器 body->login_ret = state; body->dir_id = dir_id; strcpy(body->reson, reson); Tail.pack_tail = 0x05; return this->pack();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这里的适配器,体现在这句:res_login_t* body = (res_login_t*)Body; 以及后面的部分。

解压包模块中的包,动辄几十上百种,且包大小都不一样,如果每种包都要有一个专属包体的话,那成何体统?所以包体初始化只为char*,具体情况具体定。

可用可不用的场景

我呢,弄了个中控服务器,和几个边缘服务器。
中控服务器的功能呢,转接各边缘服务器的数据通信,开放接口:accept、read、send
边缘服务器各司其职,比方说epoll吧,开放接口:accept(面向客户端)、read(面向客户端)、send(面向客户端)。

所以呢,这两个服务器之间并不能直接通信。其实也可以直接在原有功能上加一个connect的函数,然后配置信息使这条连接面向中控,在在其中读写信息。但是,我的边缘服务器都写好了,硬塞这个功能进去实在是烦,而且每个边缘服务器都有向中控服务器通信的需求,于是我干脆弄了个转接类,专门处理边缘到中介之间的转接:

class EtoC	//Edge to Command
{
private:
	int connect_fd;
public:
	EtoC();
	void Start(const char* commandIP);	//建立连接
	void send_name(char* name);			//发送认证包
	int Read_date(char* date);			//读取数据
	int get_fd(); //获取通信套接字
	int Write_date(char* date,int len);	//写入数据
};


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

功能很简单,但是足以满足它们之间连通的需求了。

这么多设计模式嘛,还是要活用,死守定律就没啥意思了。

文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。

原文链接:lion-wu.blog.csdn.net/article/details/107067488

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。