定义
使多个对象都有机会去处理请求。从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式也叫做职责链模式。
三个角色
责任链模式主要有以下三个角色:
- 抽象处理者Handler:定义一个处理请求的接口,内部包含一个后继处理者的引用。
- 具体处理者Concrete Handler:实现抽象处理者。如果能够处理请求则处理,否则就将该请求转发给它的后继处理者。
- 客户端类Client:创建处理链,同时向链头的具体处理者对象提交请求,它并不关心处理细节和请求的传递过程。
场景示例
现在多数公司请假都通过钉钉来走审批流程,不同的公司审批的规则也不同。
笔者这里以请事假为例,以及以下审批事假规则来简单讲解责任链模式。
事假天数(最小单位:天) | 审批人 |
1天 | 组长->人事经理 |
1天-7天(包含7天) | 组长->总监->人事经理 |
7天以上 | 组长->总监->老板->人事经理 |
创建请求实体类
/**
* @author zhh
* @description 事假请求实体类
* @date 2020-03-03 14:50
*/
public class PersonalLeaveRequest {
/**
* 申请人
*/
private String applicant;
/**
* 天数
*/
private Integer days;
/**
* 开始时间
*/
private String startTime;
/**
* 理由
*/
private String reason;
// 此处忽略getter、setter方法
/**
* 天数常量
*/
public interface Days {
Integer ONE = 1;
Integer SEVEN = 7;
}
}
创建抽象处理者
/**
* @author zhh
* @description 审批人
* @date 2020-03-03 14:58
*/
public abstract class Approver {
/**
* 后继审批人
*/
protected Approver approver;
/**
* 设置后继审批人
* @param approver 后继审批人
*/
public void setNextApprpver(Approver approver) {
this.approver = approver;
}
/**
* 审批
* @param request 事假请求
*/
public abstract void approve(PersonalLeaveRequest request);
}
创建具体处理者
/**
* @author zhh
* @description 老板
* @date 2020-03-03 15:11
*/
public class BossApprover extends Approver {
@Override
public void approve(PersonalLeaveRequest request) {
if (StringUtils.isNotEmpty(request.getReason())) {
System.out.println("老板审核结果: 批准");
if (approver != null) {
approver.approve(request);
}
} else {
System.out.println("老板审核结果: 不批准");
}
}
}
/**
* @author zhh
* @description 总监
* @date 2020-03-03 15:11
*/
public class InspectorGeneralApprover extends Approver {
@Override
public void approve(PersonalLeaveRequest request) {
if (StringUtils.isNotEmpty(request.getReason())) {
System.out.println("总监审核结果: 批准");
if (approver != null) {
approver.approve(request);
}
} else {
System.out.println("总监审核结果: 不批准");
}
}
}
/**
* @author zhh
* @description 组长
* @date 2020-03-03 15:07
*/
public class GroupLeaderApprover extends Approver {
@Override
public void approve(PersonalLeaveRequest request) {
if (StringUtils.isNotEmpty(request.getReason())) {
System.out.println("组长审核结果: 批准");
if (approver != null) {
approver.approve(request);
}
} else {
System.out.println("组长审核结果: 不批准");
}
}
}
/**
* @author zhh
* @description 人事经理
* @date 2020-03-03 15:07
*/
public class PersonnelManagerApprover extends Approver {
@Override
public void approve(PersonalLeaveRequest request) {
if (StringUtils.isNotEmpty(request.getReason())) {
System.out.println("人事经理审核结果: 批准");
if (approver != null) {
approver.approve(request);
}
} else {
System.out.println("人事经理审核结果: 不批准");
}
}
}
这里需要注意一下,在每个具体的处理类当中 if (approver != null) {}
这个判断是否存在后继处理者引用的分支是必须存在的。
测试类及输出
这里的测试类也可以作为我们的客户端类。
/**
* @author zhh
* @description 测试类
* @date 2020-03-03 15:23
*/
public class Test {
public static void main(String[] args) {
PersonalLeaveRequest request = new PersonalLeaveRequest();
request.setApplicant("海豪");
request.setDays(6);
request.setStartTime("2020年03月03日15:24:37");
request.setReason("家中有事");
Approver groupLeaderApprover = new GroupLeaderApprover();
Approver personnelManagerApprover = new PersonnelManagerApprover();
Approver inspectorGeneralApprover = new InspectorGeneralApprover();
Approver bossApprover = new BossApprover();
Integer days = request.getDays();
// 审批事假规则
if (PersonalLeaveRequest.Days.ONE.equals(days)) {
// 事假天数1天
groupLeaderApprover.setNextApprpver(personnelManagerApprover);
} else if (days > PersonalLeaveRequest.Days.ONE && days <= PersonalLeaveRequest.Days.SEVEN) {
// 事假天数1天-7天(包含7天)
groupLeaderApprover.setNextApprpver(inspectorGeneralApprover);
inspectorGeneralApprover.setNextApprpver(personnelManagerApprover);
} else if (days > PersonalLeaveRequest.Days.SEVEN) {
// 事假天数7天以上
groupLeaderApprover.setNextApprpver(inspectorGeneralApprover);
groupLeaderApprover.setNextApprpver(bossApprover);
bossApprover.setNextApprpver(personnelManagerApprover);
} else {
throw new RuntimeException("请假天数异常");
}
System.out.println(">>>>");
System.out.println(
String.format("[%s]发起请假申请, 请假天数[%s]天, 请假开始时间[%s], 请假理由[%s]", request.getApplicant(), request.getDays(),
request.getStartTime(), request.getReason()));
System.out.println("<<<<");
System.out.println("审核结果如下:");
groupLeaderApprover.approve(request);
}
}
测试类的输出结果如下:
>>>>
[海豪]发起请假申请, 请假天数[6]天, 请假开始时间[2020年03月03日15:24:37], 请假理由[家中有事]
<<<<
审核结果如下:
组长审核结果: 批准
总监审核结果: 批准
人事经理审核结果: 批准
类结构图
以上示例类的结构图如下所示
总结
适用场景
一个请求的处理需要多个对象当中的一个或者几个协作处理。
优点
- 降低对象之间的耦合度。对请求的发送者和接收者进行解耦。
- 责任链可以动态组合。当工作流程发生变化时,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
缺点
- 责任链较长时,请求的处理可能会涉及多个对象,从而影响系统的性能。