文章目录
- [1 Zinx框架总览](#1 Zinx框架总览)
 - [2 三层模式的分析](#2 三层模式的分析)
 - [3 三层重构原有的功能 - 头文件](#3 三层重构原有的功能 - 头文件)
 - 
- [3.1 通道层Stdin和Stdout类](#3.1 通道层Stdin和Stdout类)
 - 
- [3.1.2 StdInChannel](#3.1.2 StdInChannel)
 - [3.1.2 StdOutChannel](#3.1.2 StdOutChannel)
 
 - [3.2 协议层CmdCheck和CmdMsg类](#3.2 协议层CmdCheck和CmdMsg类)
 - 
- [3.2.1 CmdCheck单例模式](#3.2.1 CmdCheck单例模式)
 - 
- [3.2.1.1 单例模式](#3.2.1.1 单例模式)
 - [3.2.1.2 * 命令识别类向业务层不同类别做分发](#3.2.1.2 * 命令识别类向业务层不同类别做分发)
 
 - [3.2.2 CmdMsg自定义用户信息类,继承UserData](#3.2.2 CmdMsg自定义用户信息类,继承UserData)
 
 - [3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类](#3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类)
 - 
- [3.3.1 回显对象EchoRole](#3.3.1 回显对象EchoRole)
 - [3.3.2 控制输入输出](#3.3.2 控制输入输出)
 - [3.3.3 日期管理类](#3.3.3 日期管理类)
 
 
 
1 Zinx框架总览

2 三层模式的分析

3 三层重构原有的功能 - 头文件
三层结构重构原有功能
- 自定义消息类,继承UserData,添加一个成员变量szUserData
 - 定义多个Role类继承Irole,重写ProcMsg函数,进行不同处理
 - 定义protocol类,继承Iprotocol,重写四个函数,两个函数时原始
数据和用户数据之间的转换;另两个用来找消息处理对象和消息发
送对象。 - 定义channel类,继承Ichannel,在getnextinputstage函数中返回协
议对象 
3.1 通道层Stdin和Stdout类
通道类,派生自基础处理者类,提供基于系统调用的数据收发功能
一般地,用户应该根据处理的文件(信息源)不同而创建通道类的子类或选用合适的实用类(已经提供的通道类子类)来完成系统级文件IO

            
            
              c
              
              
            
          
          class StdInChannel :
	public Ichannel
{
public:
	StdInChannel();
	virtual ~StdInChannel();
	// 通过 Ichannel 继承
	virtual bool Init() override;
	virtual bool ReadFd(std::string& _input) override;
	virtual bool WriteFd(std::string& _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};
class StdOutChannel :public Ichannel
{
	// 通过 Ichannel 继承
	virtual bool Init() override;
	virtual bool ReadFd(std::string& _input) override;
	virtual bool WriteFd(std::string& _output) override;
	virtual void Fini() override;
	virtual int GetFd() override;
	virtual std::string GetChannelInfo() override;
	virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput) override;
};
        3.1.2 StdInChannel
            
            
              cpp
              
              
            
          
          bool StdInChannel::ReadFd(std::string& _input)
{
	cin >> _input;
	return true;
}
bool StdInChannel::WriteFd(std::string& _output)
{
	return false;
}
int StdInChannel::GetFd()
{
	return 0;
}
std::string StdInChannel::GetChannelInfo()
{
	return "stdin";
}
AZinxHandler* StdInChannel::GetInputNextStage(BytesMsg& _oInput)
{
	/*返回协议对象*/
	return CmdCheck::GetInstance();
}
        3.1.2 StdOutChannel
            
            
              c
              
              
            
          
          bool StdOutChannel::ReadFd(std::string& _input)
{
	return false;
}
bool StdOutChannel::WriteFd(std::string& _output)
{
	cout << _output << endl;
	return true;
}
int StdOutChannel::GetFd()
{
	return 1;
}
std::string StdOutChannel::GetChannelInfo()
{
	return "stdout";
}
AZinxHandler* StdOutChannel::GetInputNextStage(BytesMsg& _oInput)
{
	return nullptr;
}
        3.2 协议层CmdCheck和CmdMsg类
3.2.1 CmdCheck单例模式
- 原始数据和业务数据相互函数,开发者重写该函数,实现协议
 - 获取处理角色对象函数,开发者应该重写该函数,用来指定当前产生的用户数据消
 - 获取发送通道函数,开发者应该重写该函数,用来指定当前字节流应该由哪个通道对象发出
 
            
            
              csharp
              
              
            
          
          class CmdCheck :
	public Iprotocol
{
	CmdCheck();
	virtual ~CmdCheck();
	static CmdCheck *poSingle;
public:
	// 通过 Iprotocol 继承
	/*原始数据和业务数据相互函数,开发者重写该函数,实现协议*/
	virtual UserData * raw2request(std::string _szInput) override;
	virtual std::string * response2raw(UserData & _oUserData) override;
	/*获取处理角色对象函数,开发者应该重写该函数,用来指定当前产生的用户数据消息应该传递给哪个角色处理*/
	virtual Irole * GetMsgProcessor(UserDataMsg & _oUserDataMsg) override;
    /*获取发送通道函数,开发者应该重写该函数,用来指定当前字节流应该由哪个通道对象发出*/
	virtual Ichannel * GetMsgSender(BytesMsg & _oBytes) override;
	static CmdCheck *GetInstance() {
		return poSingle;
	}
	std::string szOutChannel;
};
        3.2.1.1 单例模式
构造全局唯一的协议对象
            
            
              c
              
              
            
          
          #include "CmdCheck.h"
#include "CmdMsg.h"
#include "EchoRole.h"
using namespace std;
CmdCheck *CmdCheck::poSingle = new CmdCheck();
        3.2.1.2 * 命令识别类向业务层不同类别做分发
通过是不是命令来进行区分:if (isCmd)
            
            
              c
              
              
            
          
          Irole * CmdCheck::GetMsgProcessor(UserDataMsg & _oUserDataMsg)
{
	szOutChannel = _oUserDataMsg.szInfo;
	if ("stdin" == szOutChannel)
	{
		szOutChannel = "stdout";
	}
	/*根据命令不同,交给不同的处理role对象*/
	auto rolelist = ZinxKernel::Zinx_GetAllRole();
	auto pCmdMsg = dynamic_cast<CmdMsg *>(_oUserDataMsg.poUserData);
	/*读取当前消息是否是命令*/
	bool isCmd = pCmdMsg->isCmd;
	Irole *pRetRole = NULL;
	for (Irole *prole : rolelist)
	{
		if (isCmd)
		{
			auto pOutCtrl = dynamic_cast<OutputCtrl *>(prole);
			if (NULL != pOutCtrl)
			{
				pRetRole = pOutCtrl;
				break;
			}
		}
		else
		{
			auto pDate = dynamic_cast<DatePreRole *>(prole);
			if (NULL != pDate)
			{
				pRetRole = pDate;
				break;
			}
		}
	}
	
	return pRetRole;
}
        3.2.2 CmdMsg自定义用户信息类,继承UserData
            
            
              cpp
              
              
            
          
          class CmdMsg :
	public UserData
{
public:
	/*成员变量表示要回显的字符串*/
	std::string szUserData;
	/*开启输出标志*/
	bool isOpen = true;
	/*该消息是命令*/
	bool isCmd = false;
	/*要加前缀*/
	bool needDatePre = false;
	
	CmdMsg();
	virtual ~CmdMsg();
};
        3.3 业务层:回显类, 输出通道控制类, 日期前缀管理类
3.3.1 回显对象EchoRole
主要有init, procmsg,fini三个函数
            
            
              cpp
              
              
            
          
          #pragma once
#include <zinx.h>
class EchoRole :
	public Irole
{
public:
	EchoRole();
	virtual ~EchoRole();
	// 通过 Irole 继承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
};
        - 容易出错的点:参数一必须是一个堆对象
 
            
            
              cpp
              
              
            
          
          UserData * EchoRole::ProcMsg(UserData & _poUserData)
{
	/*写出去*/
	GET_REF2DATA(CmdMsg, input, _poUserData);
	CmdMsg *pout = new CmdMsg(input);
	ZinxKernel::Zinx_SendOut(*pout, *(CmdCheck::GetInstance()));
	return nullptr;
}
        3.3.2 控制输入输出
- 写一个关闭输出的角色类,摘除输出通道或添加输出通道
 - 在CmdMsg用户数据类中添加开关标志,是否是命令标志
 - 在协议类中,根据输入字符串,设置开关标志和是否是命令的标志
 - 在协议类分发消息时,判断是否是命令,是命令则发给关闭输出角 色类,否则发给回显角色类
 
            
            
              c
              
              
            
          
          class OutputCtrl :public Irole {
	// 通过 Irole 继承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
	Ichannel *pOut = NULL;
};
        3.3.3 日期管理类
            
            
              cpp
              
              
            
          
          class DatePreRole :public Irole {
	// 通过 Irole 继承
	virtual bool Init() override;
	virtual UserData * ProcMsg(UserData & _poUserData) override;
	virtual void Fini() override;
	bool needAdd = false;
};