职责链模式
一、职责链模式的基本简介
将多个处理器链接为一个流水线,然后让要加工的对象依次经过流水线上的每一个处理器,最后到达客户手中。职责链模式可以类比为人类的工厂,工厂中的产品就是要加工的对象,产品在工厂车间中需要经过若干不同的加工步骤,每一个加工步骤就是一个处理器,工厂中的流水线将若干加工步骤连接在一起,这就构成了职责链,产品依次经过这些流水线,最终到达客户手中。
二、职责链模式的基本构成
三、组成部分介绍
- Handler
Handler
是一个抽象的处理器,定义了消息处理的抽象方法,需要由具体的子类实现,这里我们可以观察到在Handler
的handleMsg
方法中还接收了一个HandlerChain
对象的引用,这是实现处理器链式调用的关键,借助HandlerChain对象可以决定是否将当前消息传递给下一个处理器
。
- ConcreteHandler
具体的处理器,负责实现具体的消息处理逻辑,以及决定是否将消息传递给下一个处理器
- HandlerChain
HandlerChain
中关联了一组Handler
,并对外提供了添加Handler对象的接口,HandlerChain负责将添加的处理器串联起来,组成一个流水线
,除此之外,HandlerChain还提供了启动流水线的接口handleMsg(),一旦该函数被调用,整个消息便可以在HandlerChain中的流水线上被依次传递和处理,除非某个Handler阻止了消息的传递。
四、具体实现
职责链模式的实现有两个版本,一个是
数组实现
,一个是链表实现
,通过上面的介绍我们很容易有一个疑问,就是怎么把Handler串联起来,组成一个流水线?其实想想也不难,我们早就学过数据结构中的线性表,线性表不就是一种逻辑上的串联结构中,通过回忆,线性表恰有两种实现方式,一种是使用数组,一种是使用链表,而职责链模式的实现也分为这两个版本:数组版本
和链表版本
。下面我们通过模拟Tomcat中的FilterChain来实现一个简单的职责链模式的demo。
4.1 数组实现版本
4.1.1 类定义
- Filter接口
Filter接口提供对Http请求和响应的过滤和处理,对应我们上面UML图中的抽象Handler类
public interface Filter {
void doFilter(HttpRequest request, HttpResponse response, FilterChain filterChain);
}
- FilterChain
FilterChain对应着上面UML图中的HandlerChain,它提供了添加Filter的方法以及启动Filter流水线处理的方法
public class FilterChain {
private final List<Filter> filterList = new ArrayList<>();
private int curPos;
private HttpServlet servlet;
public FilterChain addFilter(Filter filter) {
filterList.add(filter);
return this;
}
public void setServlet(HttpServlet servlet) {
this.servlet = servlet;
}
public void doFilter(HttpRequest request, HttpResponse response) {
if (curPos < filterList.size()) {
System.out.println("filter[" + curPos + "]处理前");
filterList.get(curPos++).doFilter(request, response, this);
curPos--;
System.out.println("filter[" + curPos + "]处理后");
} else {
servlet.serve(request, response);
}
}
- 其他辅助类
主要包括模拟的HttpRequest请求消息,和HttpReponse响应消息,以及HttpServlet请求和响应处理类
public class HttpRequest {
public String getMethod() {
return "GET";
}
}
public class HttpResponse {
public void write(String msg) {
System.out.println(msg);
}
}
public class HttpServlet {
public void serve(HttpRequest request, HttpResponse response) {
System.out.println(request.getMethod());
response.write("404 Not Found!");
}
}
- 测试代码
public static void main(String[] args) {
FilterChain filterChain = new FilterChain();
filterChain.setServlet(new HttpServlet());
filterChain.addFilter((request, response, filterChain1) -> {
filterChain1.doFilter(request, response);
}).addFilter((request, response, filterChain13) -> {
filterChain13.doFilter(request, response);
}).addFilter((request, response, filterChain12) -> {
filterChain12.doFilter(request, response);
});
filterChain.doFilter(new HttpRequest(), new HttpResponse());
}
4.1.3 基本原理讲解
-
FilterChain中维护了一个Filter列表,该列表是数组实现,并且维护了一个curPos指针,用来指示当前经过的是第几个处理器。
-
每次调用FilterChain的doFilter方法,都会让curPos+1,为了能让请求继续被下一个Filter处理,我们只需要实现链式调用curPos+1位置上的Filter即可,直到最后一个处理器被调用,这个时候再去调用HttpServlet的处理方法,完成对消息的处理。
-
怎么实现链式调用curPos+1位置上的Filter呢?秘密就在于Filter对象本身,通过观察Filter接口,我们发现,该接口处理定义了HttpRequest和HttpResponse两个接收参数外,还定义了一个FilterChain对象的引用。然后观察FilterChain的doFilter方法实现,我们发现,在doFilter中,我们将FilterChain对象本身(this)传递给了下一个Filter,那么我们只需要在每个Filter的doFilter方法中通过filterChain引用,链式调用FilterChain对象的doFilter方法即可。这样链式调用就完成了。
4.2 链表实现版本
4.2.1 类的定义
- Filter
链表版本的Filter被设置为了一个抽象类,提供了子Filter需要的公有方法,setNextFilter和getNextFilter,分别用于设置和获取当前Filter的后继Filter。
public abstract class Filter {
private Filter nextFilter;
public void setNextFilter(Filter nextFilter) {
this.nextFilter = nextFilter;
}
public Filter getNextFilter() {
return nextFilter;
}
public abstract void doFilter(HttpRequest request, HttpResponse response, FilterChain fc);
}
- FilterChain
链表版本的FilterChlain和数组版本的FilterChain的基本功能是一样的,只不过链表版本的FilterChain采用的是链表结构构建Filter流水线。其中curFilter相当于数组实现中的curPos,指示当前正在执行的Filter对象,链表实现中的Filter流水线的链式调用的本质其实和数组没有差别,在目前这个设计中。FilterChain中的doFilter方法每次调用都会将curFilter指针往后移动,而每个Filter对象又持有FilterChain对象的引用,这样只需要在Filter对象中的doFilter方法中继续调用fc.doFilter即可完成链式调用。一旦curFilter为空,说明所有的Filter都被调用过了,这个时候就可以调用servlet的处理逻辑。
public class FilterChain {
private Filter headFilter;
private Filter tailFilter;
private Filter curFilter;
private HttpServlet servlet;
public FilterChain addFilter(Filter filter) {
filter.setNextFilter(null);
if (headFilter == null) {
headFilter = filter;
curFilter = headFilter;
} else {
tailFilter.setNextFilter(filter);
}
tailFilter = filter;
return this;
}
public void setServlet(HttpServlet servlet) {
this.servlet = servlet;
}
public void doFilter(HttpRequest request, HttpResponse response) {
if (curFilter != null) {
Filter filter = curFilter;
curFilter = curFilter.getNextFilter();
filter.doFilter(request, response, this);
} else {
servlet.serve(request, response);
}
}
}
- 测试代码
public static void main(String[] args) {
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new Filter() {
@Override
public void doFilter(HttpRequest request, HttpResponse response, FilterChain fc) {
System.out.println("filter1处理前");
fc.doFilter(request, response);
System.out.println("filter1处理后");
}
}).addFilter(new Filter() {
@Override
public void doFilter(HttpRequest request, HttpResponse response, FilterChain fc) {
System.out.println("filter2处理前");
fc.doFilter(request, response);
System.out.println("filter2处理后");
}
});
filterChain.setServlet(new HttpServlet());
filterChain.doFilter(new HttpRequest(), new HttpResponse());
}