👉文章示例代码👈

定义

使多个对象都有机会去处理请求。从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

责任链模式也叫做职责链模式

三个角色

责任链模式主要有以下三个角色:

  • 抽象处理者Handler:定义一个处理请求的接口,内部包含一个后继处理者的引用。
  • 具体处理者Concrete Handler:实现抽象处理者。如果能够处理请求则处理,否则就将该请求转发给它的后继处理者。
  • 客户端类Client:创建处理链,同时向链头的具体处理者对象提交请求,它并不关心处理细节和请求的传递过程。

场景示例

现在多数公司请假都通过钉钉来走审批流程,不同的公司审批的规则也不同。

笔者这里以请事假为例,以及以下审批事假规则来简单讲解责任链模式。

事假天数(最小单位:天) 审批人
1天 组长->人事经理
1天-7天(包含7天) 组长->总监->人事经理
7天以上 组长->总监->老板->人事经理

创建请求实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* @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;
}
}

创建抽象处理者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* @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);
}

创建具体处理者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* @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) {} 这个判断是否存在后继处理者引用的分支是必须存在的。

测试类及输出

这里的测试类也可以作为我们的客户端类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* @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], 请假理由[家中有事]
<<<<
审核结果如下:
组长审核结果: 批准
总监审核结果: 批准
人事经理审核结果: 批准

类结构图

以上示例类的结构图如下所示
image.png

总结

适用场景

一个请求的处理需要多个对象当中的一个或者几个协作处理。

优点

  • 降低对象之间的耦合度。对请求的发送者和接收者进行解耦。
  • 责任链可以动态组合。当工作流程发生变化时,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。

缺点

  • 责任链较长时,请求的处理可能会涉及多个对象,从而影响系统的性能。

参考