1、责任链模式
责任链(Chain of Responsibility)模式就是一个“推卸责任”或者说找到合适的处理对象,不是自己处理的或者处理不了的就交给下一个去处理。这样可以使每个处理对象专注于自己的事情,不是自己的事甩给后面处理,但是这样会使得处理处理延迟,这就需要我们去权衡两者的利弊。
责任链可以弱化“请求方”和“处理方”的关联关系,让各自可以都可成为独立复用的组件。“弱化“请求方”和“处理方”的关联关系”这句话怎么理解呢?就是假如不使用责任链模式,那么请求方或者处理方必须知道谁该处理什么请求,这会降低可复用组件的独立性
2、责任链模式实现
代码UML图如下:
代码如下:
/*** 发生问题的类*/public class Trouble {private int number;public Trouble(int number) {this.number = number;}public int getNumber() {return number;}@Overridepublic String toString() {return "Trouble{" +"number=" + number +'}';}}
/*** 解决问题的抽象类*/public abstract class Support {private String name;private Support next;public Support(String name) {this.name = name;}public Support setNext(Support next) {this.next = next;//关键return next;}//解决问题的步骤public final void support(Trouble trouble) {if (resolve(trouble)) {done(trouble);} else if (next != null) {next.support(trouble);} else {fail(trouble);}}protected abstract boolean resolve(Trouble trouble) ;protected void done(Trouble trouble) {System.out.println(trouble + "is resolved by" + this + ".");}protected void fail(Trouble trouble) {System.out.println(trouble + "cannot be resolved.");}}
/*** 这是一个永远不解决问题的类*/public class NoSupport extends Support{public NoSupport(String name) {super(name);}protected boolean resolve(Trouble trouble) {return false;}}
/*** 只解决编号小于limit的问题*/public class LimitSupport extends Support{private int limit;public LimitSupport(String name, int limit) {super(name);this.limit = limit;}protected boolean resolve(Trouble trouble) {if (trouble.getNumber() < limit) {return true;}return false;}}
/*** 只解决奇数编号的问题*/public class OddSupport extends Support{public OddSupport(String name) {super(name);}protected boolean resolve(Trouble trouble) {if (trouble.getNumber() % 2 == 1) {return true;}return false;}}
/*** 只处理特定编号的问题*/public class SpecialSupport extends Support{private int number;public SpecialSupport(String name, int number) {super(name);this.number = number;}protected boolean resolve(Trouble trouble) {if (trouble.getNumber() != number)return false;else return true;}}
public class Main {public static void main(String[] args) {Support useless = new NoSupport("useless");Support limit = new LimitSupport("limit",10);Support special = new SpecialSupport("special", 222);Support limit2 = new LimitSupport("limit2", 333);Support odd = new OddSupport("odd");//形成指责链useless.setNext(limit).setNext(special).setNext(limit2).setNext(odd);//制造各种问题for (int i = 0; i < 500; i++) {useless.support(new Trouble(i));}}}
这种责任链模式实现会将请求依次传给下一个处理器,无论前面的处理器有没有处理过请求;另外一种实现是如果请求被处理了,那么将不会传给下一个处理器。
还可以使用数组或者链表来实现责任链模式,即通过遍历数组或者链表里面的处理器即可。
3、责任链模式的应用
最典型的应用就是Tomcat的过滤器,还有Okhttp3中Interceptor以及Netty中ChannelInBoundHandlerAdapter。
3.1、责任链模式如何提高代码的拓展性
责任链模式可以让代码满足“开闭原则”,比如我们需要对用户提交的内容进行敏感词过滤,那么我们可以在相应的方法上添加相关处理逻辑,但是这样就违反了开闭原则。如果使用了责任链模式,那么就可以直接添加一个新的类来处理即可。
4、在框架中的责任链模式代码分析
4.1、Tomcat的ApplicationFilterChain
public final class ApplicationFilterChain implements FilterChain {private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];private int pos = 0;//当前执行到了哪个filterprivate int n = 0;//filter的个数private Servlet servlet = null;@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if( Globals.IS_SECURITY_ENABLED ) {final ServletRequest req = request;final ServletResponse res = response;try {java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Void>() {@Overridepublic Void run()throws ServletException, IOException {//该方法会对过滤器进行遍历internalDoFilter(req,res);return null;}});}}}private void internalDoFilter(ServletRequest request,ServletResponse response)throws IOException, ServletException {// 如果还有过滤器,那么就调用下一个过滤器if (pos < n) {ApplicationFilterConfig filterConfig = filters[pos++];try {Filter filter = filterConfig.getFilter();if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);}if( Globals.IS_SECURITY_ENABLED ) {final ServletRequest req = request;final ServletResponse res = response;Principal principal =((HttpServletRequest) req).getUserPrincipal();Object[] args = new Object[]{req, res, this};SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);} else {//递归调用下一个过滤器filter.doFilter(request, response, this);}return;}}}void addFilter(ApplicationFilterConfig filterConfig) {// 防止同一个过滤器被重复加入for(ApplicationFilterConfig filter:filters)if(filter==filterConfig)return;if (n == filters.length) {//扩容ApplicationFilterConfig[] newFilters =new ApplicationFilterConfig[n + INCREMENT];System.arraycopy(filters, 0, newFilters, 0, n);filters = newFilters;}filters[n++] = filterConfig;}}
