前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我用过的设计模式(4)-- 责任链模式

我用过的设计模式(4)-- 责任链模式

原创
作者头像
看、未来
修改2021-02-26 10:14:24
2610
修改2021-02-26 10:14:24
举报
在这里插入图片描述
在这里插入图片描述

前言

刚接触责任链的时候,我不是很喜欢这个模式,因为我不知道它能拿来干什么用啊。

直到后来写那个FTP项目的时候,我用责任链+调停者优化了我的epoll模块之后,我爱死这个模式了!!!


责任链模式

什么是责任链模式呢?我们来看个小故事:

最近给团队里的程序员们分了个等级,模仿着阿里的那套模式,将我们团队里人分为P6/P7/P8/P9/P10。

来活儿的时候呢,就这样分配,根据难度初步估计,分配给对应的等级的程序员去做,难度等级7级就给P7,8级就给P8。

但是这样会有个什么问题呢?其实也没啥问题,就是这好像不需要用类,直接在场景main里面放一堆的if来判断就好了。

那如果分配到当前等级的人他不收呢?那就得移交到下一个等级去,这要是用ifelse来判断,可想而知代码将会有多么的拥挤。

而且将本不属于场景类的任务强加到场景类之中,似乎也不合情理。

所以,我们采用这样一个方法:创建一个责任类,将各级程序员按等级排序,当有任务来临时,依次向后,如果能接那就接了,轮到最后还没人接,那就退了,默认没人接。

这,就是责任链模式。

这个图是很简单的嘞:

在这里插入图片描述
在这里插入图片描述

乍一看,平平无奇,甚至还会感觉:鸡肋。

先看一下代码实现,然后再看这个模式是如何让我对epoll模块化腐朽为神奇的!!!

示例代码

代码语言:txt
复制
#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文件管理项目(本地云)项目日报(六)


在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 责任链模式
    • 示例代码
    • 第一个epoll模块
    • 使用责任链模式优化过的epoll模块
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档