c++编解码封装
多态版编解码
对服务器和客户端的结构体进行序列化然后对数据进行反序列化
案例分析
代码demo
Codec.h
#pragma once
#include <iostream>
class Codec
{
public:
Codec();
virtual std::string encodeMsg();//string是标准库的string类
virtual void* decodeMsg();
virtual ~Codec();
};
RequesetCodec.h
#pragma once
#include "Codec.h"
#include "Message.pb.h"
#include <iostream>
using namespace std;
struct RequestInfo
{
//默认私有的
int cmd;
string clientID;
string serverID;
string sign;
string data;
};
class RequestCodec : public Codec
{
public:
//空对象
RequestCodec();
//解码
RequestCodec(string encstr);//序列化后的字符串
//编码
RequestCodec(RequestInfo* info);
//init函数给空构造准备的
//解码
void initMessage(string encstr);
//编码
void initMessage(RequestInfo* info);
//重写父类函数 -> 序列化函数 -> 序列化的字符串
string encodeMsg();
//重写父类函数 -> 反序列化函数 -> 返回的是结构体/类对象
void* decodeMsg();
~RequestCodec();
private:
//保存解码的字符串
string m_encStr;//接收编码
//要序列化的数据在这个类中,通过这个类进行序列化操作
RequestMsg m_msg;//protobuf结构体
};
RequesetCodec.h
#include "RequesetCodec.h"
//空对象
RequestCodec::RequestCodec()
{
}
//解码
RequestCodec::RequestCodec(string encstr)
{
initMessage(encstr);
}
//编码
RequestCodec::RequestCodec(RequestInfo* info)
{
initMessage(info);
}
//init函数给空构造准备的
//解码
void RequestCodec::initMessage(string encstr)
{
m_encStr = encstr;
}
//编码
void RequestCodec::initMessage(RequestInfo* info)
{
m_msg.set_cmdtype(info->cmd);
m_msg.set_clientid(info->clientID);
m_msg.set_serverid(info->serverID);
m_msg.set_sign(info->sign);
m_msg.set_data(info->data);
}
//重写父类函数 -> 序列化函数 -> 序列化的字符串
string RequestCodec::encodeMsg()
{
string output;
m_msg.SerializeToString(&output);
return output;
}
//重写父类函数 -> 反序列化函数 -> 返回的是结构体/类对象
void* RequestCodec::decodeMsg()
{
m_msg.ParseFromString(m_encStr);
return &m_msg;
}
RequestCodec::~RequestCodec()
{
}
test.cpp
触发多态:
#include<iostream>
using namespace std;
#include"Codec.h"
#include"RequesetCodec.h"
#include"RespondCodec.h"
//编码
string encodeMsg(Codec* codec)
{
return codec->encodeMsg();
}
//解码
void* decodeMsg(Codec* codec)
{
return codec->decodeMsg();
}
int main()
{
RequestInfo reqInfo;
reqInfo.cmd = 9;
reqInfo.clientID = "Onepiece";
reqInfo.serverID = "Luffy";
reqInfo.data = "我是要成为海贼王的男人";
reqInfo.sign = "hahahahahahaha";
RequestCodec req(&reqInfo);
//编码
string reqmsg = encodeMsg(&req);
//解码
RequestCodec reql(reqmsg);
RequestMsg* reqMsg = (RequestMsg*)decodeMsg(&reql);
cout << "cmdtype: " << reqMsg->cmdtype()
<< ", clientID: " << reqMsg->clientid()
<< ", serverID: " << reqMsg->serverid()
<< ", data: " << reqMsg->data()
<< ", sign: " << reqMsg->sign() << endl;
RespondInfo resInfo;
resInfo.status = false;
resInfo.clientID = "黑崎一护";
resInfo.serverID = "朽木露琪亚";
resInfo.data = "死神";
resInfo.seckeyID = 666;
RespondCodec res(&resInfo);
//编码
string resmsg = encodeMsg(&res);
//解码
RespondCodec resl(resmsg);
RespondMsg* resMsg = (RespondMsg*)decodeMsg(&resl);
cout << "cmdtype: " << resMsg->status()
<< ", clientID: " << resMsg->clientid()
<< ", serverID: " << resMsg->serverid()
<< ", data: " << resMsg->data()
<< ", sign: " << resMsg->seckeyid() << endl;
}
工厂模式版编解码
工厂模式(用到多态)
工厂模式的作用
工厂模式的作用是用来创建对象的,那么创建对象的工作实际上是交给了某一个去做。
简单工厂模式–只需1个工厂类
工厂: 使用一个单独的类来做创建实例的过程, 这就是工厂。
简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。
特点:
- 缺点:每添一个对象,就需要对简单工厂进行修改(尽管不是删代码,仅仅是添一个switch case,但仍然违背了“不改代码”的原则)
- 优点:去除了与具体产品的依赖, 实现简单。
# 简单工厂模式的使用:
1. 创建一个工厂类
2. 在这个类中提供一个公共的成员方法
- 创建对象, 一般情况下创建某些实现多态的子类对象
- 返回这个对象的地址
案例
// 通过创建工厂类, 添加工厂函数, 创建对象
// 两个编解码的子类
class RequestCodec : public Codec // 编解码请求数据
class RespondCodec : public Codec // 编解码响应数据
/*
知识点:
做条件判断的时候, if..else if .. else 效率比 switch 低
如果判断的情况比较少使用 if .. else
如果情况比较多, 建议使用 switch
*/
// 创建工厂类, 创建编解码对象
//demo1
class Factory
{
public:
Factory();
~Factory();
// 工厂函数, 创建对象
// flag==1 -> RequestCodec
// flag==2 -> RespondCodec
Codec* createObject(int flag)
{
// 判断
if(flag == 1)
{
RequestCodec* req = new RequestCodec();
return req;
}
else if(flag == 2)
{
RequestCodec* res = new RespondCodec();
return res;
}
}
}
//demo2
class Factory
{
public:
Factory();
~Factory();
// 工厂函数, 创建对象
// flag==1 -> RequestCodec
// flag==2 -> RespondCodec
Codec* createObject(int flag)
{
Codec* c = NULL;
// 判断
if(flag == 1)
{
c = new RequestCodec();
}
else if(flag == 2)
{
c = new RespondCodec();
}
return c;
}
}
工厂类的使用:
// 1. 创建工厂类对象
Factory* fac = new Factory;
// 2. 通过工厂函数创建编解码对象
Codec* c = fac->createObject(1);
// 3. 编码
string str = c->encoceMsg();
上面这个案例并没有满足需求,假设子类又多了一个,又要在工厂类进行添加---->这是改原来写好的代码
工厂模式–需要N个工厂类
工厂方法:每种产品由一种工厂来创建,一个工厂保存一个new
特点:基本完美,完全遵循 “不改代码”的原则
# 工厂模式流程
1. 创建一个工厂类的基类
2. 在这个基类中定义一个虚函数 -> 创建对象的方法
3. 创建子工厂类(编解码的基类有多少子类, 就创建多少个子工厂类)
- 每个编解码的子类, 都对应一个工厂类
4. 在子工厂类中重写工厂类基类中的虚函数
工厂类的使用:
// 两个编解码的子类
class RequestCodec : public Codec
class RespondCodec : public Codec
class TestCodec : public Codec // 编解码响应数据
使用:
// 创建工厂类的基类
class BaseFactory
{
public:
BaseFactory();
~BaseFactory;
virtual Codec* createObject()
{
return NULL;
}
}
// 工厂类子类
class RequestFactory : public BaseFactory
{
public:
RequestFactory();
~RequestFactory;
Codec* createObject()
{
return new RequestCodec;
}
}
class RespondFactory : public BaseFactory
{
public:
RespondFactory();
~RespondFactory;
Codec* createObject()
{
return new RespondCodec;
}
}
class TestFactory : public BaseFactory
{
public:
TestFactory();
~TestFactory;
Codec* createObject()
{
return new TestCodec;
}
}
这样就不需要修改原来的代码,只需要添加新的子类就行了
工厂模式使用
// 1. 创建工厂类对象
BaseFactory* fac = new RespondFactory;
// 2. 得到了编解码对象
Codec* c = fac->createObject();
// 3. 编码
string str = c->encodeMsg();
工厂模式实况
工厂类的基类 demo
#pragma once
#include "Codec.h"
class CodecFactory
{
public:
CodecFactory();
virtual Codec* createCodec();
virtual ~CodecFactory();
};
工厂类的子类.h demo
#pragma once
#include "CodecFactory.h"
#include "Codec.h"
#include "RequesetCodec.h"
#include <iostream>
class RequestFactory : public CodecFactory
{
public:
RequestFactory(std::string enc);
RequestFactory(RequestInfo* info);
Codec* createCodec();
~RequestFactory();
private:
bool m_flag;
std::string m_encStr;
RequestInfo* m_info;
};
工程类的子类.cpp demo
#include "RequestFactory.h"
RequestFactory::RequestFactory(std::string enc) //: CodecFactory()
{
m_flag = false;
m_encStr = enc;
}
RequestFactory::RequestFactory(RequestInfo* info)//:CodecFactory()
{
m_flag = true;
m_info = info;
}
Codec* RequestFactory::createCodec()
{
Codec* codec = NULL;
if (m_flag)
{
codec = new RequestCodec(m_info);
}
else
{
codec = new RequestCodec(m_encStr);
}
return codec;
}
RequestFactory::~RequestFactory()
{
}
main.cpp
#include <iostream>
#include "RespondCodec.h"
#include "RespondCodec.h"
#include "Codec.h"
#include "RequestFactory.h"
#include "RespondFactory.h"
using namespace std;
int main()
{
// 数据编码
RequestInfo info{ 1, "client", "server", "x00911", "hello, world" };//结构体初始化
CodecFactory* factory = new RequestFactory(&info);
Codec* codec = factory->createCodec();
string str = codec->encodeMsg();
cout << "序列化数据: " << str << endl;
delete factory;
delete codec;
// 数据解码
factory = new RequestFactory(str);
codec = factory->createCodec();
RequestMsg* r1 = (RequestMsg*)codec->decodeMsg();
cout << "cmdtype: " << r1->cmdtype()
<< ", clinetID: " << r1->clientid()
<< ", serverID: " << r1->serverid()
<< ", sign: " << r1->sign()
<< ", data: " << r1->data() << endl;
delete factory;
delete codec;
cout << endl << "=========================" << endl;
RespondInfo resinfo{ 1, 999, "luffy", "zoro", "change world 666 !" };
factory = new RespondFactory(&resinfo);
codec = factory->createCodec();
str = codec->encodeMsg();
delete factory;
delete codec;
factory = new RespondFactory(str);
codec = factory->createCodec();
RespondMsg* r2 = (RespondMsg*)codec->decodeMsg();
cout << "status: " << r2->status()
<< ", seckeyID: " << r2->seckeyid()
<< ", clinetID: " << r2->clientid()
<< ", serverID: " << r2->serverid()
<< ", data: " << r2->data() << endl;
delete factory;
delete codec;
return 0;
}