做者:Java3y
连接:https://zhuanlan.zhihu.com/p/...
来源:知乎
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。java
在说责任链模式以前,咱们先来聊聊「过滤器」。git
过滤器相信你们都确定学过了,在最开始学Servlet的时候咱们会学到Filter
。等学到Struts2的时候,咱们会学到Interceptor
。等学到SpringMVC的时候,咱们会学到HandlerInterceptor
。github
但不管学哪一个框架,咱们发现是最终其实它仍是作Filter
这么一件事。说白了就是:设计模式
在个人 GitHub对Filter,HandlerInterceptor,Interceptor都有讲到,若是想要复习的同窗不妨进去搜索关键字「 过滤器」「 Struts2」「 SpringMVC」
为何看责任链模式要聊「过滤器」呢?后面会讲到,不要着急。框架
举个例子:把咱们的正常请求想象成一堆的杂物,里边有米豆,有鸡蛋,有敖丙公仔玩具等等一些杂物。ide
如今咱们想要最后获得的是米豆,鸡蛋和敖丙玩具都被过滤掉。因而咱们就能够搞两个滤网,把敖丙玩具和鸡蛋给过滤掉。工具
以最快的方式,咱们能够写if
来把这个需求给搞掂,下面上代码。学习
一个请求,咱们使用Request
对象来表示:ui
public class Request { // 请求的数据 private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } }
针对请求,咱们确定是有一个接口处理请求的啦,咱们使用Handler
来表示:this
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 } }
上面的代码你们不知道熟不熟悉,反正我就很熟悉,不少时候我就是这样写代码的(在现实里边不少代码就是这样的)。
在某年某月产品过来告诉我,须要新增一种类型想要过滤的「白菜」
在某年某月产品过来告诉我,须要新增一种类型想要过滤的「鸡腿」
在某年某月产品过来告诉我,须要新增一种类型想要过滤的「鸡头」
因而咱们的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<Filter> 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); } }
若是我告诉你,这种的处理方式就是责任链模式,你会怎么想?
再来回顾一下,我作了些什么:
if
和方法
)Chain
链起来,暴露一个方法给Handler使用下面我画了一张对比图:
是否是很简单?说到底仍是抽象了一层(将每一个处理抽象为一个类而已)。
那为何要这样干?若是我要增长一个处理流程,我是得新增一个处理类,而后在链上增长相对应的类。操做也的确如此。
这不麻烦吗?要便捷的话,我还不如直接增长一个if
,一个处理方法来得方便呢。
用责任链模式的好处就是分工明确,解耦,容易维护。
if else
耦合性相对较低。Handler
处理类,不会影响到BaseHandler
的代码责任链模式的缺点:
doChain
方法,而里边由多个处理类来组成,还得看相应的调用顺序)咱们从上面也能够看到责任链模式主要有如下特色:
有这两个特色我就称这些代码运用了责任链模式。在翻阅资料或者看书的时候,你可能会看到:“纯责任链和不纯责任链”
还有就是将各个具体的Handler串成一条链,这里边的实现会有各式各样的:
new
出一个ArrayList,而后在构造方法里边代码手动add到ArrayList的其实没必要要在乎纯和不纯的责任链模式,咱们学设计模式是为了学它的思想。
在文章最开头我就说了咱们之前学过的Filter,其实Filter就是用了责任链模式。咱们来简单看看代码:
咱们在使用Filter过滤器的时候,要么在XML上配置<filter>
,要么在代码上写上注解@WebFilter(filterName = "",urlPatterns = "")
这些配置都会在Web容器启动的时候被读取,读完这些配置,会将你写的Filter过滤器加到FilterChain里边:
咱们能够看到Filter接口下有不少都实现了doFilter
:
JavaWeb的Filter实际用到的也是责任链模式。
设计模式自己不是一件很复杂的东西,像门面模式,模板方法模式都很是容易理解。学完了会有一种感受:“啊?就这?”
重要的是学完能不能用到实际的工做中,这是很是难能难得的。咱们写代码按照自身的思惟写if else
是很是简单的,而设计模式每每须要绕一个圈才能把功能实现。
可是,合理运用设计模式的代码是很是好维护的。若是你懂设计模式,那代码会看起来很是清晰。若是你不懂设计模式,你就会感叹“这代码是真的骚阿”(这就是我...)。
好好学习,但愿有朝一日,别人看到个人代码,在背后说「这人写的代码是真的骚,牛逼阿」。