1.设计思路
正常的解耦,在c++有两种,通过基于对象的回调方式,或者利用接口编程。网络模块与业务模块的解耦,这里采用的是回调机制。
我们对业务进行编号,网络模块在接收到数据之后,解析出业务对象的编号,然后根据业务编号,去map容器里面找到改业务编号对应的处理函数,然后获取到处理函数的句柄,执行即可。
2.实现
2.1业务编号
#ifndef PUBLIC_H
#define PUBLIC_H/*
server和client的公共文件
*/
enum EnMsgType
{
LOGIN_MSG = 1, // 登录消息
LOGIN_MSG_ACK, // 登录响应消息
LOGINOUT_MSG, // 注销消息
REG_MSG, // 注册消息
REG_MSG_ACK, // 注册响应消息
ONE_CHAT_MSG, // 聊天消息
ADD_FRIEND_MSG, // 添加好友消息CREATE_GROUP_MSG, // 创建群组
ADD_GROUP_MSG, // 加入群组
GROUP_CHAT_MSG, // 群聊天
};#endif
以后只要包含该头文件即可,获取业务编号 ,这样也方便业务扩展,降低了业务和网络的耦合关系。
2.2业务注册
业务注册是业务模块的事情,但是这里为了更好的表达清楚,介绍一下。
业务模块是单例对象,里面包含一个map容器,存储着业务id号和业务对应的函数。
// 存储消息id和其对应的业务处理方法
unordered_map<int, MsgHandler> _msgHandlerMap;
业务注册是在业务模块的构造函数里面注册
// 注册消息以及对应的Handler回调操作
ChatService::ChatService()
{
// 用户基本业务管理相关事件处理回调注册
_msgHandlerMap.insert({LOGIN_MSG, std::bind(&ChatService::login, this, _1, _2, _3)});
_msgHandlerMap.insert({LOGINOUT_MSG, std::bind(&ChatService::loginout, this, _1, _2, _3)});
_msgHandlerMap.insert({REG_MSG, std::bind(&ChatService::reg, this, _1, _2, _3)});
_msgHandlerMap.insert({ONE_CHAT_MSG, std::bind(&ChatService::oneChat, this, _1, _2, _3)});
_msgHandlerMap.insert({ADD_FRIEND_MSG, std::bind(&ChatService::addFriend, this, _1, _2, _3)});// 群组业务管理相关事件处理回调注册
_msgHandlerMap.insert({CREATE_GROUP_MSG, std::bind(&ChatService::createGroup, this, _1, _2, _3)});
_msgHandlerMap.insert({ADD_GROUP_MSG, std::bind(&ChatService::addGroup, this, _1, _2, _3)});
_msgHandlerMap.insert({GROUP_CHAT_MSG, std::bind(&ChatService::groupChat, this, _1, _2, _3)});
}
3.网路模块和业务模块的联系
网路模块和业务模块解耦了,彼此之间是互不影响的。
// 数据的反序列化
json js = json::parse(buf);
// 达到的目的:完全解耦网络模块的代码和业务模块的代码
//msgid就是事务id
// 通过js["msgid"] 获取=》业务handler=》conn js time
auto msgHandler = ChatService::instance()->getHandler(js["msgid"].get<int>());
// 回调消息绑定好的事件处理器,来执行相应的业务处理
msgHandler(conn, js, time);
网路根据业务id,获取业务对应的函数句柄,执行即可。