Luckylau's Blog

设计模式之责任链模式

​ 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。

常见的流程如下:

发送者知道链中的第一个接受者,它向这个接受者发出请求;

每一个接受者都对请求进行分析,要么处理它,要么往下传递;

每一个接受者知道的其他对象只有一个,即它的下家对象;

如果没有任何接受者处理请求,那么请求将从链上离开,不同的实现对此有不同的反应。

​ 以请假流程为例,一般公司普通员工的请假流程简化如下:普通员工发起一个请假申请,当请假天数小于3天时只需要得到主管批准即可;当请假天数大于3天时,主管批准后还需要提交给经理审批,经理审批通过,若请假天数大于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
public class LeaveApproval {
public boolean process(String request, int number) {
boolean result = handleByDirector(request); // 主管处理
if (result == false) { // 主管不批准
return false;
} else if (number < 3) { // 主管批准且天数小于 3
return true;
}
result = handleByManager(request); // 准管批准且天数大于等于 3,提交给经理处理
if (result == false) { // 经理不批准
return false;
} else if (number < 7) { // 经理批准且天数小于 7
return true;
}
result = handleByTopManager(request); // 经理批准且天数大于等于 7,提交给总经理处理
if (result == false) { // 总经理不批准
return false;
}
return true; // 总经理最后批准
}
public boolean handleByDirector(String request) {
// 主管处理该请假申请
}
public boolean handleByManager(String request) {
// 经理处理该请假申请
}
public boolean handleByTopManager(String request) {
// 总经理处理该请假申请
}
}

​ 该方案存在几个问题:LeaveApproval 类比较庞大,各个上级的审批方法都集中在该类中,违反了 “单一职责原则”,测试和维护难度大;当需要修改该请假流程,譬如增加当天数大于30天时还需提交给董事长处理,必须修改该类源代码(并重新进行严格地测试),违反了 “开闭原则”;该流程缺乏灵活性,流程确定后不可再修改(除非修改源代码),客户端无法定制流程。

责任链的角色:
Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。

ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

1
2
3
4
5
6
@Data
@AllArgsConstructor
public class LeaveRequest {
private String name; // 请假人姓名
private int numOfDays; // 请假天数
}
1
2
3
4
5
6
7
8
9
10
11
@Data
public abstract class Handler {
protected String name; // 处理者姓名
protected Handler nextHandler; // 下一个处理者
public Handler(String name) {
this.name = name;
}
public abstract boolean process(LeaveRequest leaveRequest); // 处理请假
}
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
// 主管处理者
public class Director extends Handler {
public Director(String name) {
super(name);
}
@Override
public boolean process(LeaveRequest leaveRequest) {
boolean result = (new Random().nextInt(10)) > 3; // 随机数大于3则为批准,否则不批准
String log = "主管<%s> 审批 <%s> 的请假申请,请假天数: <%d> ,审批结果:<%s> ";
System.out.println(String.format(log, this.name, leaveRequest.getName(), leaveRequest.getNumOfDays(), result == true ? "批准" : "不批准"));
if (result == false) { // 不批准
return false;
} else if (leaveRequest.getNumOfDays() < 3) { // 批准且天数小于3,返回true
return true;
}
return nextHandler.process(leaveRequest); // 批准且天数大于等于3,提交给下一个处理者处理
}
}
// 经理
public class Manager extends Handler {
public Manager(String name) {
super(name);
}
@Override
public boolean process(LeaveRequest leaveRequest) {
boolean result = (new Random().nextInt(10)) > 3; // 随机数大于3则为批准,否则不批准
String log = "经理<%s> 审批 <%s> 的请假申请,请假天数: <%d> ,审批结果:<%s> ";
System.out.println(String.format(log, this.name, leaveRequest.getName(), leaveRequest.getNumOfDays(), result == true ? "批准" : "不批准"));
if (result == false) { // 不批准
return false;
} else if (leaveRequest.getNumOfDays() < 7) { // 批准且天数小于7
return true;
}
return nextHandler.process(leaveRequest); // 批准且天数大于等于7,提交给下一个处理者处理
}
}
// 总经理
public class TopManager extends Handler {
public TopManager(String name) {
super(name);
}
@Override
public boolean process(LeaveRequest leaveRequest) {
boolean result = (new Random().nextInt(10)) > 3; // 随机数大于3则为批准,否则不批准
String log = "总经理<%s> 审批 <%s> 的请假申请,请假天数: <%d> ,审批结果:<%s> ";
System.out.println(String.format(log, this.name, leaveRequest.getName(), leaveRequest.getNumOfDays(), result == true ? "批准" : "不批准"));
if (result == false) { // 总经理不批准
return false;
}
return true; // 总经理最后批准
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Client {
public static void main(String[] args) {
Handler zhangsan = new Director("张三");
Handler lisi = new Manager("李四");
Handler wangwu = new TopManager("王五");
// 创建责任链
zhangsan.setNextHandler(lisi);
lisi.setNextHandler(wangwu);
// 发起请假申请
boolean result1 = zhangsan.process(new LeaveRequest("小旋锋", 1));
System.out.println("最终结果:" + result1 + "\n");
boolean result2 = zhangsan.process(new LeaveRequest("小旋锋", 4));
System.out.println("最终结果:" + result2 + "\n");
boolean result3 = zhangsan.process(new LeaveRequest("小旋锋", 8));
System.out.println("最终结果:" + result3 + "\n");
}
}
Luckylau wechat
如果对您有价值,看官可以打赏的!