责任链模式,又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求处理者通过前一对象记住其下一个对象的引用而成一条链;当有请求发生时,可将请求沿着这条链传递,传递过程中每一个对象都对其进行处理,直到达到限定条件不能处理为止。
举例:学校收取某项费用,此时由底层向上层处理链路可能如下所示:

由学生到最上级校长之间一级一级传递,每一级都有自己的下级负责人,当达到阈值,如上图中校长没有下级负责人,此时处理终止。也可能是某个班级自发的购买班服,则上图达到班级A就没有下级负责人,责任链终止。
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。
现需要开发一个请假流程控制系统。请假1天(不满1天按一天算)到3天的假只需要小组长同意即可;请假3天到7天的假还需要部门经理同意;请假7天以上的假还需要总经理同意才行。
类图如下:

- /**
- * 定义请假条
- */
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class LeaveRequest {
- // 姓名
- private String name;
- // 请假天数
- private int num;
- // 请假内容
- private String content;
- }
- /**
- * 处理者抽象类
- */
- public abstract class Handler {
- protected final static int NUM_ONE = 1;
- protected final static int NUM_THREE = 3;
- protected final static int NUM_SEVEN = 7;
- // 该领导处理的请假天数区间
- private int numStart;
- private int numEnd;
-
- // 领导上面还有领导
- private Handler nextHandler;
-
- // 设置请假天数范围,上不封顶
- public Handler(int numStart){
- this.numStart = numStart;
- }
- // 设置请假天数范围
- public Handler(int numStart, int numEnd){
- this.numStart = numStart;
- this.numEnd = numEnd;
- }
-
- // 设置上级领导
- public void setNextHandler(Handler nextHandler){
- this.nextHandler = nextHandler;
- }
-
- // 各级领导处理请假条的方式
- public abstract void handlerLeave(LeaveRequest leave);
-
- // 提交请假条
- public final void submit(LeaveRequest leave){
- if(leave.getNum() == 0){
- return;
- }
- // 如果请假天数达到该领导的处理要求
- if(leave.getNum() >= this.numStart){
- // 该领导处理
- this.handlerLeave(leave);
-
- // 如果还有上级,并且请假天数超过了当前领导的处理上限
- if(this.nextHandler != null && leave.getNum() > numEnd){
- // 继续提交
- this.nextHandler.submit(leave);
- }else{
- System.out.println("流程结束...");
- }
- }
- }
- }
- /**
- * 小组长
- */
- public class GroupLeader extends Handler{
- public GroupLeader() {
- //小组长处理1-3天的请假
- super(Handler.NUM_ONE, Handler.NUM_THREE);
- }
-
- @Override
- public void handlerLeave(LeaveRequest leave) {
- System.out.println(leave.getName() + "请假" + leave.getNum() + "天" + ", 请假内容为:" + leave.getContent() + "。");
- System.out.println("小组长批准...");
- }
- }
-
-
- /**
- * 部门经理
- */
- public class Manager extends Handler{
- public Manager() {
- // 部门经理处理3-7天的假条
- super(Handler.NUM_THREE, Handler.NUM_SEVEN);
- }
-
- @Override
- public void handlerLeave(LeaveRequest leave) {
- System.out.println(leave.getName() + "请假" + leave.getNum() + "天" + ", 请假内容为:" + leave.getContent() + "。");
- System.out.println("部门经理批准...");
- }
- }
-
-
-
- /**
- * 总经理
- */
- public class GeneralManager extends Handler{
- public GeneralManager() {
- super(Handler.NUM_SEVEN);
- }
-
- @Override
- public void handlerLeave(LeaveRequest leave) {
- System.out.println(leave.getName() + "请假" + leave.getNum() + "天" + ", 请假内容为:" + leave.getContent() + "。");
- System.out.println("总经理批准...");
- }
- }
- public class Client {
- public static void main(String[] args) {
- // 定义各位领导及其上级
- GroupLeader groupLeader = new GroupLeader();
- Manager manager = new Manager();
- GeneralManager generalManager = new GeneralManager();
- groupLeader.setNextHandler(manager);
- manager.setNextHandler(generalManager);
-
- // 定义一个请假条
- LeaveRequest leaveRequest = new LeaveRequest("张三", 42, "身体不适");
- groupLeader.submit(leaveRequest);
-
- }
- }
结果如下:


对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。