4.职责链模式
(1).概述
在现实生活中,常常会出现这样的案列: 一个请求由多个对象处理,但每一个对象的处理条件的权限不同。列如: 公司员工请假,可皮甲的领导有不么负责人、总经理、副经理等,但每个领导能批准的天数不同,员工必须根据自己请假的天数去找不同的领导签名,也即是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的列子还有很多,如找领导出差报销、生活中的"击鼓传花"游戏等。
定义:
又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有的请求的处理者通过前以对象记住下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
(2).结构
职责链模式主要包含以下角色:
- 抽象处理者角色: 定义一个处理请求的
接口
,包含抽象处理方法和一个后继连接。 - 具体处理者角色:
实现抽象处理者的处理方法
,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后续者。 - 客户类角色: 创建处理链,并相信链头的具体处理者对象提交请求,
它不关心处理细节和请求的传递过程
。
(3).案列实现
现需要开发一个请假流程控制系统。请假一天以上的假只需要小组长同意即可;请假一天到三天的假还需要部门经理同意;请求3天到7天的还需要总经理同意才行。
类图如下:
1、如果父类没有定义有参构造函数(或者存在有参构造方法,但是无参构造方法也有),
子类则不需要显式定义构造方法
。2、如果父类有显式定义有参构造方法且没有显示无参构造方法,则子类必须显式定义有参构造方法,
并且在构造方法中使用super(XX)显式调用父类的有参构造方法
请假条
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:08 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: LeaveRequest * @Description: TODO 请假类 * @Version 1.0 */ public class LeaveRequest { // 姓名 private String name; // 请假条 private int num; //请假内容 private String content; public LeaveRequest(String name, int num, String content) { this.name = name; this.num = num; this.content = content; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
抽象处理者角色
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:10 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: Handler * @Description: TODO 抽象处理者 * @Version 1.0 */ public abstract class Handler { // 定义常量 protected final static int NUM_ONE=1; protected final static int NUM_TWO=3; protected final static int NUM_THREE=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; } // 各级领导处理请求条的放啊 protected abstract void handlerLeave(LeaveRequest leaveRequest); // 提交请假条 public final void submit(LeaveRequest leaveRequest){ // 该领导进行审批 this.handlerLeave(leaveRequest); if (this.nextHandler!=null&&leaveRequest.getNum()>this.numEnd){ //假如有后继领导,且请求的天数大于自己的最大天数,那么就交给下一任领导处理 this.nextHandler.submit(leaveRequest); //把请假条给下一任 }else { System.out.println("流程结束...."); } } }
具体处理者
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:23 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: GroupLeader * @Description: TODO 小组长 * @Version 1.0 */ public class GroupLeader extends Handler{ public GroupLeader(){ super(0,NUM_ONE); } @Override protected void handlerLeave(LeaveRequest leaveRequest) { System.out.println(leaveRequest.getName()+"请假 "+leaveRequest.getNum()+" 天"+leaveRequest.getContent()); System.out.println("小组长审批: 同意"); } }
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:27 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: Manger * @Description: TODO 经理 * @Version 1.0 */ public class Manger extends Handler{ public Manger(){ super(NUM_ONE,NUM_TWO); } @Override protected void handlerLeave(LeaveRequest leaveRequest) { System.out.println(leaveRequest.getName()+"请假 "+leaveRequest.getNum()+" 天"+leaveRequest.getContent()); System.out.println("经理审批: 同意"); } }
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:28 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: BigLeader * @Description: TODO * @Version 1.0 */ public class BigLeader extends Handler{ public BigLeader(){ super(NUM_TWO,NUM_THREE); } @Override protected void handlerLeave(LeaveRequest leaveRequest) { System.out.println(leaveRequest.getName()+"请假 "+leaveRequest.getNum()+" 天"+leaveRequest.getContent()); System.out.println("总经理审批: 同意"); } }
客户类角色
package com.jsxs.behavioralModel.responsibility; /** * @Author Jsxs * @Date 2023/4/23 15:41 * @PackageName:com.jsxs.behavioralModel.responsibility * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { // 创建一个请假条 LeaveRequest leaveRequest = new LeaveRequest("jsxs", 5, "身体不适"); // 创建各级领导对象 GroupLeader groupLeader = new GroupLeader(); Manger manger = new Manger(); BigLeader bigLeader = new BigLeader(); // 添加上级领导 groupLeader.setNextHandler(manger); manger.setNextHandler(bigLeader); // bigLeader.setNextHandler(null); // jsxs提交请假申请 groupLeader.submit(leaveRequest); } }
(4).优缺点
优点:
- 降低了对象间的耦合度: 该模式降低了请求发送者和接收者的耦合度
- 增加了系统的可扩展性: 可以根据需要增加新的请求处理类,满足
开闭原则
。 - 增强了给对象指派职责的灵活性: 当工作流程发生变化,可以动态的改变链内的成员或者修改它们的次序,也可以动态的新增或者删除责任。
- 责任链简化了对象之间的连接: 一个对象只需保持指向其后继者的引用,不需要保持其他处理者的引用,这避免了使用总舵的if或者if .else语句。
- 责任分担: 每个类只需处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理(
请假七天以上
),该请求可能一致传到链的末端都得不到处理。 - 对比较长的职责链,请求的处理可能设计多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
(5).JDK源码分析
在JavaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析。