10.责任链模式(Chain of Responsibility)
1.定义:
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
责任链模式是一种对象的行为模式。
2.通用代码
这个模式很简单,也许看完通用代码就能理解了:
package _10ChainOfResponsibility; public abstract class Handler { private Handler nextHandler; public final void service(String request) { // 判断自己能否提供服务,如果不能,将任务提交给下一个处理者 if(this.canIService()) { this.realService(); }else{ if(null != nextHandler) { // 将任务提交给下一个处理者 nextHandler.service(request); }else{ // 我没权限处理,又找不到我的上级,不知道该怎么办了 } } } public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; } // 根据一定条件判断我能否提供服务 protected abstract boolean canIService(); // 真正的服务方法 protected abstract void realService(); }
3.责任链模式的两个角色
- 抽象处理者(Handler)角色: 定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。Handler类的聚合关系给出了具体子类对下家的 引用,抽象方法service()规范了子类处理请求的操作。
- 具体处理者(ConcreteHandler)角色: 具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
4.使用场景
来考虑这样一个功能:申请聚餐费用的管理。
很多公司都是这样的福利,就是项目组或者是部门可以向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动。
申请聚餐费用的大致流程一般是:由申请人先填写申请单,然后交给领导审批,如果申请批准下来,领导会通知申请人审批通过,然后申请人去财务领取费用,如果没有批准下来,领导会通知申请人审批未通过,此事也就此作罢。
不同级别的领导,对于审批的额度是不一样的,比如,项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。
也就是说,当某人提出聚餐费用申请的请求后,该请求会经由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求。
可以使用责任链模式来实现上述功能:当某人提出聚餐费用申请的请求后,该请求会在 项目经理—〉部门经理—〉总经理
这样一条领导处理链上进行传递,发出请求的人并不知道谁会来处理他的请求,每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级别的领导,只要有领导处理了,传递就结束了。
需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态地组合职责链,实现不同的功能要求了。
下面来看用责任链模式实现的上述功能:
package _10ChainOfResponsibility; public abstract class FeeHandler { private FeeHandler nextHandler; public final boolean handleFeeRequest(int fee) { // 判断自己是否有资格审批,如果不能,将任务提交给上级处理 if(this.canIService(fee)) { this.realService(fee); }else{ if(null != nextHandler) { // 将任务提交给上级 return nextHandler.handleFeeRequest(fee); } } return false; } public void setNextHandler(FeeHandler nextHandler) { this.nextHandler = nextHandler; } // 根据金额判断我能否审批 protected abstract boolean canIService(int fee); // 真正的审批方法 protected abstract void realService(int fee); }
package _10ChainOfResponsibility; //项目经理 public class ProjectManagerHandler extends FeeHandler { @Override protected boolean canIService(int fee) { if(fee > 500) { System.out.println(fee+"元,项目经理没权限审批"); return false; } return true; } @Override protected void realService(int fee) { System.out.println(fee+"元,项目经理批了"); } }
package _10ChainOfResponsibility; // 部门经理 public class DeptManagerHandler extends FeeHandler { @Override protected boolean canIService(int fee) { if(fee > 1000) { System.out.println(fee+"元,部门经理没权限审批"); return false; } return true; } @Override protected void realService(int fee) { System.out.println(fee+"元,部门经理批了"); } }
package _10ChainOfResponsibility; //总经理 public class GeneralManagerHandler extends FeeHandler { @Override protected boolean canIService(int fee) { // 总经理就是牛,多少金额都能批 return true; } @Override protected void realService(int fee) { System.out.println(fee+"元,总经理批了"); } }
package _10ChainOfResponsibility; public class Client { /** * @param args */ public static void main(String[] args) { ProjectManagerHandler pmh = new ProjectManagerHandler(); DeptManagerHandler dmh = new DeptManagerHandler(); GeneralManagerHandler gmh = new GeneralManagerHandler(); pmh.setNextHandler(dmh); dmh.setNextHandler(gmh); System.out.println("张三找PM报销餐费300"); pmh.handleFeeRequest(300); System.out.println("张三找PM报销餐费600"); pmh.handleFeeRequest(600); System.out.println("张三找PM报销餐费2000"); pmh.handleFeeRequest(2000); } }
300元,项目经理批了
张三找PM报销餐费600
600元,项目经理没权限审批
600元,部门经理批了
张三找PM报销餐费2000
2000元,项目经理没权限审批
2000元,部门经理没权限审批
2000元,总经理批了
5.纯的与不纯的责任链模式
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。
6.责任链模式的优点
责任链模式非常显著的优点是将请求和处理分开。请求者可以不知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦,提高系统的灵活性。
7.责任链模式的缺点
责任链模式有两个非常显著的缺点:
- 一是性能问题,每个请求都要从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
- 二是调试不方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑比较复杂。
8.责任链模式的注意事项
责任链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经超过了其阀值,超过则不允许该链建立,避免无意识地破坏系统性能。
9.实际使用示例
众所周知Tomcat中的Filter就是使用了责任链模式,创建一个Filter除了要在web.xml文件中做相应配置外,还需要实现javax.servlet.Filter接口。
public class TestFilter implements Filter{ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } public void destroy() { } public void init(FilterConfig filterConfig) throws ServletException { } }
上一篇: JVM使用总结