文章目录
- 1 添加转大写字母输出功能
- 2 责任链模式
- 2.1 责任链的设计
- 2.2 责任链的实现
- 2.3 责任链的测试
- 3 代码重构
- 3.1 类图设计
- 3.2 重构设计 - 头文件
- 3.3 重构实现
1 添加转大写字母输出功能
功能流程:
- stdin通道类中包含一个功能处理类对象
- 功能处理类中包含一个stdout类对象
- 数据被读取到stdin通道,stdin通道将其交给功能处理类对象,该对象判断数据特点后转大写或直接交个stdout类对象进行输出
class process_func {
public:void DataProc(string &_input){string output = _input;transform(output.begin(), output.end(), output.begin(),::toupper);poOut->DataPush(output);}
} *poProcess = new process_func();/class stdin_channel :public Ichannel {
public:// 通过 Ichannel 继承virtual bool ReadFd(std::string & _input) override{cin >> _input;return true;}virtual bool WriteFd(std::string & _output) override{return false;}virtual int GetFd() override{return 0;}virtual bool DataProcess(std::string & _data) override{poProcess->DataProc(_data);return true;}
};
2 责任链模式
通道类和功能处理类的对象都是整个流程中的环节,将这些环节连起来则形成责任链。
处理者类设计:
- 提供handle函数作为链式处理的入口
- handle内部执行当前环节的处理,并执行下一阶段的处理函数,直到没有下一环节
- 提供internalhandle纯虚函数用来执行本环节处理
- 提供getnext纯虚函数用来获取下一环节
消息类设计:
- 只提供虚析构函数,用户可自行扩展
2.1 责任链的设计
/*责任链设计*/
class IZinxMsg {
public:IZinxMsg() {}virtual ~IZinxMsg() {}
};class AZinxHandler {
public:AZinxHandler() {}virtual ~AZinxHandler() {}void Handle(IZinxMsg &_oInput);
protected:virtual IZinxMsg *InternelHandle(IZinxMsg &_oInput) = 0;virtual AZinxHandler *GetNextHandler(IZinxMsg &_oNextMsg) = 0;
};
2.2 责任链的实现
/*责任链实现*/
void AZinxHandler::Handle(IZinxMsg & _oInput)
{IZinxMsg *poNextMsg = NULL;AZinxHandler *poNextHandler = NULL;poNextMsg = InternelHandle(_oInput);if (NULL != poNextMsg){/*下一个环节处理*/poNextHandler = GetNextHandler(*poNextMsg);/*有下一个环节才处理*/if (NULL != poNextHandler){poNextHandler->Handle(*poNextMsg);}delete poNextMsg;}return;
}
2.3 责任链的测试
/*责任链测试:将一串字符串交给处理者1进行首字母大写并输出,然后转交给处理者2进行字符统计并输出*/
class str_msg :public IZinxMsg {
public:str_msg(string &_content):content(_content) {}string content;
};class h2_Count :public AZinxHandler {// 通过 AZinxHandler 继承virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override{auto input = dynamic_cast<str_msg&>(_oInput);cout << "处理者2处理开始" << endl;cout << input.content.size() << endl;cout << "处理者2处理结束" << endl;return NULL;}virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override{return nullptr;}
} h2;class h1_UpperFirst :public AZinxHandler {// 通过 AZinxHandler 继承virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override{auto input = dynamic_cast<str_msg&>(_oInput);cout << "处理者1处理开始" << endl;str_msg *pret = new str_msg(input.content);auto head = pret->content.begin();transform(head, head+1, head, ::toupper);cout << pret->content << endl;cout << "处理者1处理结束" << endl;return pret;}virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override{return &h2;}
} h1;int main()
{string input = "hello";str_msg input_msg(input);h1.Handle(input_msg);
}
3 代码重构
3.1 类图设计
3.2 重构设计 - 头文件
重构通道类和功能处理类(继承handler类):
- 通道类的data_process函数不要了,通过重写internelhandle实现
- 功能处理类的dataproc函数不要了,通过重写internelhandle实现
- stdin类通过重写getnext方法返回功能处理对象
- 功能处理类重写getnext方法返回stdout对象
重构kernel类:
- epoll中不再执行channel类的方法,替换成handler类的handle方法
- kernel类判断当前epoll的触发方向并将其封装为消息类对象传递给通道类
- kernel增加函数用来处理程序向外发送数据(取代直接调用通道类的sendout函数)
创建消息类(继承message类):
- 创建IO方向类用来让epoll给channel对象传递当前ready的IO方向
- 创建byte消息类用来让channel对象给功能处理对象传递待处理字符串
- 逐级继承保证消息内容丰富性
/*重构类---设计*/#define GET_REF2DATA(type, ref, orig) type * pref = dynamic_cast<type *>(&orig); if (nullptr == pref) {return nullptr;} type &ref = dynamic_cast<type&>(orig)class IZinxMsg {
public:IZinxMsg() {}virtual ~IZinxMsg() {}
};class SysIOReadyMsg :public IZinxMsg {
public:enum IO_DIC {IN, OUT} m_emIoDic;SysIOReadyMsg(IO_DIC _dic) :m_emIoDic(_dic) {}
};class BytesMsg :public SysIOReadyMsg {
public:BytesMsg(SysIOReadyMsg &_base) :SysIOReadyMsg(_base.m_emIoDic) {}std::string szData;
};//class AZinxHandler {
public:AZinxHandler() {}virtual ~AZinxHandler() {}void Handle(IZinxMsg &_oInput);
protected:virtual IZinxMsg *InternelHandle(IZinxMsg &_oInput) = 0;virtual AZinxHandler *GetNextHandler(IZinxMsg &_oNextMsg) = 0;
};class Ichannel:public AZinxHandler {
public:virtual bool ReadFd(std::string &_input) = 0;virtual bool WriteFd(std::string &_output) = 0;virtual int GetFd() = 0;void DataSendOut();void DataPush(std::string &_data);std::list<std::string> m_write_buffer;virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override;
};class ZinxKernel {static void Zinx_SendOut(std::string &_output, Ichannel &_oChannel);
};
3.3 重构实现
/*重构实现*/
void ZinxKernel::Zinx_Run()
{int iEpollRet = -1;for(;;){struct epoll_event atmpEvent[100];iEpollRet = epoll_wait(GetInstance()->iEpollFd, atmpEvent, 100, -1);if (-1 == iEpollRet){if (EINTR == errno){continue;}else{break;}}for (int i = 0; i < iEpollRet; i++){Ichannel *poChannel = static_cast<Ichannel *>(atmpEvent[i].data.ptr);if (0 != (EPOLLIN & atmpEvent[i].events)){string input;SysIOReadyMsg IoStat = SysIOReadyMsg(SysIOReadyMsg::IN);poChannel->Handle(IoStat);}if (0 != (EPOLLOUT & atmpEvent[i].events)){poChannel->DataSendOut();if (poChannel->m_write_buffer.empty()){Zinx_ClearChannelOut(*poChannel);}}}}
}void ZinxKernel::Zinx_SendOut(std::string & _output, Ichannel & _oChannel)
{SysIOReadyMsg iodic = SysIOReadyMsg(SysIOReadyMsg::OUT);BytesMsg oBytes = BytesMsg(iodic);oBytes.szData = _output;_oChannel.Handle(oBytes);
}IZinxMsg * Ichannel::InternelHandle(IZinxMsg & _oInput)
{IZinxMsg *poRet = NULL;GET_REF2DATA(SysIOReadyMsg, oIoStat, _oInput);if (oIoStat.m_emIoDic == SysIOReadyMsg::IN){BytesMsg *poBytes = new BytesMsg(oIoStat);if (true == ReadFd(poBytes->szData)){poRet = poBytes;}else{delete poBytes;}}else if (oIoStat.m_emIoDic == SysIOReadyMsg::OUT){GET_REF2DATA(BytesMsg, oBytes, _oInput);if (true == m_write_buffer.empty()){ZinxKernel::Zinx_SetChannelOut(*this);}m_write_buffer.push_back(oBytes.szData);}return poRet;
}
/*重构后测试*/
#include "Zinx.h"
#include <algorithm>
using namespace std;class stdout_channel :public Ichannel {
public:virtual bool ReadFd(std::string & _input) override{return false;}virtual bool WriteFd(std::string & _output) override{cout << _output << endl;return true;}virtual int GetFd() override{return 1;}virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override{return nullptr;}} *poOut = new stdout_channel();class process_func :public AZinxHandler{
public:void DataProc(string &_input){string output = _input;transform(output.begin(), output.end(), output.begin(),::toupper);poOut->DataPush(output);}virtual IZinxMsg * InternelHandle(IZinxMsg & _oInput) override{GET_REF2DATA(BytesMsg, input, _oInput);string output = input.szData;transform(output.begin(), output.end(), output.begin(), ::toupper);ZinxKernel::Zinx_SendOut(output, *poOut);return NULL;}virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override{return nullptr;}
} *poProcess = new process_func();class stdin_channel :public Ichannel {
public:virtual bool ReadFd(std::string & _input) override{cin >> _input;return true;}virtual bool WriteFd(std::string & _output) override{return false;}virtual int GetFd() override{return 0;}virtual AZinxHandler * GetNextHandler(IZinxMsg & _oNextMsg) override{return poProcess;}};int main()
{ZinxKernel::ZinxKernelInit();ZinxKernel::Zinx_Add_Channel(*(new stdin_channel()));ZinxKernel::Zinx_Add_Channel(*poOut);ZinxKernel::Zinx_Run();ZinxKernel::ZinxKernelFini();
}