java filter 责任链模式_看懂了责任链模式,你就能明白很多

前言

只有光头才能变强。

最近在看项目代码的时候发现「责任链模式」,于是想花点时间来写写什么是责任链模式。

不知道大家是怎么学习设计模式的,一般我都是用到的时候,或者接触到的时候才会去学。否则感觉学完就很容易就忘掉了,不能理解为什么要使用设计模式(因为没有真实的场景给我去使用)。

在之前我已经更新说几篇设计模式的文章了,我觉得写得「还行」,有兴趣的同学可以到我的GitHub上,关键字搜索「设计模式」,就能找到对应的文章。

c79d930281e2431a434668177536b5ca.png

不得不说,我现在负责项目的代码我常常会感叹:这代码怎么这么骚啊!项目里边用到了很多的设计模式,在最开始看的时候会很费劲(因为之前没学),但维护起来是真的方便。

一、什么是责任链模式?

在说责任链模式之前,我们先来聊聊「过滤器」。

过滤器相信大家都肯定学过了,在最开始学Servlet的时候我们会学到Filter。等学到Struts2的时候,我们会学到Interceptor。等学到SpringMVC的时候,我们会学到HandlerInterceptor。

但无论学哪个框架,我们发现是最终其实它还是做Filter这么一件事。说白了就是:

把所有的过滤器都放在FilterChain里边,依次执行每个过滤器。

在我的GitHub对Filter,HandlerInterceptor,Interceptor都有讲到,如果想要复习的同学不妨进去搜索关键字「过滤器」「Struts2」「SpringMVC」

4d9f472383d67ae9a20873f239d0e542.png

为什么看责任链模式要聊「过滤器」呢?后面会讲到,不要着急。

1.1 干掉敖丙和鸡蛋

举个例子:把我们的正常请求想象成一堆的杂物,里边有米豆,有鸡蛋,有敖丙公仔玩具等等一些杂物。

786dc468107d91c716dd3ab676458142.png

现在我们想要最后得到的是米豆,鸡蛋和敖丙玩具都被过滤掉。于是我们就可以搞两个滤网,把敖丙玩具和鸡蛋给过滤掉。

以最快的方式,我们可以写if来把这个需求给搞掂,下面上代码。

一个请求,我们使用Request对象来表示:

public class Request {

// 请求的数据

private String data;

public String getData() {

return data;

}

public void setData(String data) {

this.data = data;

}

}

针对请求,我们肯定是有一个接口处理请求的啦,我们使用Handler来表示:

public class Handler {

public void handlerRequest(Request request) {

// 得到请求的数据

String data = request.getData();

if (data.contains("鸡蛋")) {

filterEgg(data);

}

if (data.contains("敖丙工具")) {

filterAoBing(data);

}

// 我到这里就能拿到米豆了。

}

private void filterAoBing(String data) {

//doSomething

}

private void filterEgg(String data) {

//doSomething

}

}

上面的代码大家不知道熟不熟悉,反正我就很熟悉,很多时候我就是这样写代码的(在现实里边很多代码就是这样的)。

1.2 如何更加优雅干掉敖丙和鸡蛋?

在某年某月产品过来告诉我,需要新增一种类型想要过滤的「白菜」

在某年某月产品过来告诉我,需要新增一种类型想要过滤的「鸡腿」

在某年某月产品过来告诉我,需要新增一种类型想要过滤的「鸡头」

于是我们的Handler处理就可能「膨胀」起来了,可能是这样?

public class Handler {

public void handlerRequest(Request request) {

// 得到请求的数据

String data = request.getData();

if (data.contains("鸡蛋")) {

filterEgg(data);

}

if (data.contains("敖丙工具")) {

filterAoBing(data);

}

if (data.contains("白菜")) {

filterBaiCai(data);

}

if (data.contains("鸡头")) {

filterJiTou(data);

}

if (data.contains("鸡腿")) {

filterJiTui(data);

}

// 我到这里就能拿到米豆了。

}

private void filterJiTou(String data) {

//doSomething

}

private void filterJiTui(String data) {

//doSomething

}

private void filterAoBing(String data) {

//doSomething

}

private void filterEgg(String data) {

//doSomething

}

}

明显的是,如果处理的流程改动比较大的话(需要增删改其中的某个流程),那我每次都需要更改handlerRequest的代码,增加/修改/删除一个if和一个处理方法。

更加面向对象的方式是这样的:将每个处理的方式抽象成一个类,每个类各司其职。

无论是过滤敖丙还是过滤鸡蛋还是过滤米豆,做的事都是过滤。我们就可以将其抽象成接口。于是我们就有一个接口,多个实现类。

public interface Filter {

// 过滤

void doFilter(String data);

}

class FilterEgg implements Filter {

@Override

public void doFilter(String data) {

//doSomething

}

}

class FilterAoBing implements Filter {

@Override

public void doFilter(String data) {

//doSomething

}

}

class FilterBaiCai implements Filter {

@Override

public void doFilter(String data) {

//doSomething

}

}

class FilterJiTou implements Filter {

@Override

public void doFilter(String data) {

//doSomething

}

}

每个各司其职的Filter都有可能被执行,我们可以将其串成一条链,抽象一层对外只暴露一个方法来替代if。于是我们可以写出一个FilterChain类

public class FilterChain {

List filters = new ArrayList<>();

public FilterChain() {

filters.add(new FilterEgg());

filters.add(new FilterAoBing());

filters.add(new FilterBaiCai());

filters.add(new FilterJiTou());

}

public void processData(String data) {

for (Filter filter : filters) {

filter.doFilter(data);

}

}

}

改造过后,我们的Handler就长这个样子了:

public class Handler {

public void handlerRequest(Request request) {

// 得到请求的数据

String data = request.getData();

FilterChain filterChain = new FilterChain();

// 处理数据

filterChain.processData(data);

}

}

如果我告诉你,这种的处理方式就是责任链模式,你会怎么想?

二、为什么责任链模式?

再来回顾一下,我做了些什么:

将处理的各个流程抽象为各个类(本来Handler里边有多个if和方法)

将多个类用Chain链起来,暴露一个方法给Handler使用

done

下面我画了一张对比图:

fe5f20551d9b5b6b2aaeaaee38678caa.png

是不是很简单?说到底还是抽象了一层(将每个处理抽象为一个类而已)。

4eac662fea8c85cc6e1916befdad1ecc.png

那为什么要这样干?如果我要增加一个处理流程,我是得新增一个处理类,然后在链上增加相对应的类。操作也的确如此。

这不麻烦吗?要便捷的话,我还不如直接增加一个if,一个处理方法来得方便呢。

用责任链模式的好处就是分工明确,解耦,容易维护。

将多个条件判定分散到各个的处理类上,相对于if else耦合性相对较低。

增加一个具体的Handler处理类,不会影响到BaseHandler的代码

责任链模式的缺点:

项目里边会有多个具体Handler类(因为每种处理都抽象为一个类,所以会有多个类)

不好调试,初看代码时不好阅读。(对外只是一个doChain方法,而里边由多个处理类来组成,还得看相应的调用顺序)

三、再来聊聊责任链模式

我们从上面也可以看到责任链模式主要有以下特点:

一个Handler接口,多个Handler处理类

多个Handler处理类串起来形成一条链

有这两个特点我就称这些代码运用了责任链模式。在翻阅资料或者看书的时候,你可能会看到:“纯责任链和不纯责任链”

纯:请求执行到某个具体的Handler,该Handler要么自行处理然后结束请求,要么不处理继续往下给别的Handler执行。

不纯:请求执行到某个具体的Handler,该Handler自行处理了,还继续往下给别的Handler执行。

还有就是将各个具体的Handler串成一条链,这里边的实现会有各式各样的:

在我例子里是直接new出一个ArrayList,然后在构造方法里边代码手动add到ArrayList的

有可能会在代码里边每个具体Handler都会记录自己下一个Handler是谁

有可能将Handler的初始化放在XML上

....//反正各种操作最终还是会将各个Handler串起来。

其实不必要在意纯和不纯的责任链模式,我们学设计模式是为了学它的思想。

四、看看JavaWeb的Filter

在文章最开头我就说了我们以前学过的Filter,其实Filter就是用了责任链模式。我们来简单看看代码:

我们在使用Filter过滤器的时候,要么在XML上配置,要么在代码上写上注解@WebFilter(filterName = "",urlPatterns = "")

这些配置都会在Web容器启动的时候被读取,读完这些配置,会将你写的Filter过滤器加到FilterChain里边:

5d890fa47dccbcef7817dec24e5ef8ea.png

我们可以看到Filter接口下有很多都实现了doFilter:

3913699b255d5e30d4f2f369cf0abe5e.png

JavaWeb的Filter实际用到的也是责任链模式。

最后

设计模式本身不是一件很复杂的东西,像门面模式,模板方法模式都非常容易理解。学完了会有一种感觉:“啊?就这?”

重要的是学完能不能用到实际的工作中,这是非常难能可贵的。我们写代码按照自身的思维写if else是非常简单的,而设计模式往往需要绕一个圈才能把功能实现。

但是,合理运用设计模式的代码是非常好维护的。如果你懂设计模式,那代码会看起来非常清晰。如果你不懂设计模式,你就会感叹“这代码是真的骚阿”(这就是我...)。

好好学习,希望有朝一日,别人看到我的代码,在背后说「这人写的代码是真的骚,牛逼阿」。

参考资料:

乐于输出干货的Java技术公众号:Java3y。公众号内有300多篇原创技术文章、海量视频资源、精美脑图,关注即可获取!

f23edeaf8eb832d2daf076c87c9ce1ff.gif

非常感谢人才们能看到这里,如果这个文章写得还不错,觉得「三歪」我有点东西的话 求点赞 求关注️ 求分享👥 求留言💬 对暖男我来说真的 非常有用!!!

创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值