文章目录
-
- 前言
- 责任链模式
-
- 示例代码
- 第一个epoll模块
- 使用责任链模式优化过的epoll模块
前言
刚接触责任链的时候,我不是很喜欢这个模式,因为我不知道它能拿来干什么用啊。
直到后来写那个FTP项目的时候,我用责任链 调停者优化了我的epoll模块之后,我爱死这个模式了!!!
责任链模式
什么是责任链模式呢?我们来看个小故事:
最近给团队里的程序员们分了个等级,模仿着阿里的那套模式,将我们团队里人分为P6/P7/P8/P9/P10。
来活儿的时候呢,就这样分配,根据难度初步估计,分配给对应的等级的程序员去做,难度等级7级就给P7,8级就给P8。
但是这样会有个什么问题呢?其实也没啥问题,就是这好像不需要用类,直接在场景main里面放一堆的if来判断就好了。
那如果分配到当前等级的人他不收呢?那就得移交到下一个等级去,这要是用ifelse来判断,可想而知代码将会有多么的拥挤。
而且将本不属于场景类的任务强加到场景类之中,似乎也不合情理。
所以,我们采用这样一个方法:创建一个责任类,将各级程序员按等级排序,当有任务来临时,依次向后,如果能接那就接了,轮到最后还没人接,那就退了,默认没人接。
这,就是责任链模式。
这个图是很简单的嘞:
乍一看,平平无奇,甚至还会感觉:鸡肋。
先看一下代码实现,然后再看这个模式是如何让我对epoll模块化腐朽为神奇的!!!
示例代码
代码语言:javascript复制#include<iostream>
using namespace std;
//抽象任务类
class abstractRW {
public:
virtual int get_diff() = 0; //获取任务等级
virtual string get_RW() = 0; //获取任务内容
};
//具体任务类
class RW:public abstractRW{
protected:
int diff = 0;
string str = " ";
public:
RW(int diff, string str) {
this->diff = diff;
this->str = str;
}
int get_diff() { return this->diff; } //设置任务等级
string get_RW() { return this->str; } //设置任务内容
};
//任务分配类
class handle {
private:
int level = 5;
handle* nexthandle;
protected:
virtual void respon(abstractRW* rw) = 0;
public:
handle(int l) { this->level = l; }
void handleMessage(abstractRW* rw) {
if (rw->get_diff() == this->level)
this->respon(rw);
else
{
if (this->nexthandle != NULL)
this->nexthandle->handleMessage(rw);
else
cout << "没人接" << endl;
}
}
void setNext(handle* h) { this->nexthandle = h; }
};
class P6 :public handle {
public:
P6(int lev) :handle(lev){} //继承写法
void respon(abstractRW* rw) {
cout << rw->get_RW() << " P6接了" << endl;
}
};
class P7 :public handle {
public:
P7(int lev) :handle(lev) {}
void respon(abstractRW* rw) {
cout << rw->get_RW() << " P7接了" << endl;
}
};
class P8 :public handle {
public:
void respon(abstractRW* rw) {
cout << rw->get_RW() << " P8接了" << endl;
}
};
int main()
{
abstractRW* rw = new RW(7,"没事儿");
handle* h6 = new P6(6);
handle* h7 = new P7(7);
h6->setNext(h7);
h6->handleMessage(rw);
return 0;
}
第一个epoll模块
我第一次接触epoll,是在培训班的项目中。那也是我写的第一个Linux网络编程相关的项目。
但是只有一个念想:把老师给的案例吃透,仿写,能动。
时间紧任务重,我的手上还带着团队呢,我要让我的团队,快速运转。
旧的类图是这样的:
类图里少画了一个SOCK对象,和一个心跳模块的对象。
可以看出,这个epoll类完全成为了前置服务器的中枢神经,负重前行,前置服务器中所有的对象它都要管。
但是,它也只是个功能模块啊,怎么忍心让它负担这么重???
使用责任链模式优化过的epoll模块
秉着“单一职责原则”,我认为epoll只需要且只能监听文件描述符,但是它不应该知道消息内容,更不应该对消息进行处理。
这个问题确实也困扰了我,我想了好久,因为我以前的做法都是epoll收到消息后,判断是哪个地方来的消息,如果是监听套接字,则判定是有新连接上来,处理连接(这里就需要将网络连接模块和epoll模块放在一起,这是其一);如果是通信套接字(客户端)来的消息,那么就是客户端有消息上来,还要判断是否空包(空包为客户端掉线,需要处理),若不是空包,则对包进行一个基本的判断(这里就需要解压包模块的介入,这是其二),之后将包发往中控服务器(这里就需要进程间通信模块的介入,这是其三);对包的处理与转发还使用了小型线程池(这就需要线程池模块的参与,这是其四),此外,还有日志模块和心跳检测模块,这么多东西,如今一锅炖在epoll模型中,成何体统?
但是又有什么办法呢?请求来了,自然是要回应的啊,要回应,就需要各个模块之间的配合了,我思来想去,想到了责任链模式。
我以前一直觉得这个模式简直是鸡肋,但是这次之后我改观了,没有鸡肋的设计模式,只有鸡肋的设计师。设计模式的优势是什么?
- 将请求和处理分开。
- 请求者可以不知道是谁处理了,处理者也不用知道请求者的全貌。
- 两者解耦,提高系统的灵活性。
于是便有了以下这张图,也正是这张图吸引了听我讲这个项目设计的朋友们:
现在epoll就可以专心干自己的事情了。
具体实现以及对图的释义,我当时有日报纪录:FTP文件管理项目(本地云)项目日报(六)