本文为笔者在阅读一些书籍、博客、专栏等资料后所总结的个人对于责任链模式的笔记,由于笔者才疏学浅,若有不足之处,还望各位加以斧正,您的建议与鼓励都是笔者源源不断的前进动力。感谢!
文章大纲如下:
- 责任链模式的简单认识
- 责任链模式的简单应用
- 两种责任链的实现方法:基于数组、链表
- 责任链的一些简单应用
- 责任链模式在源码中的体现
- 责任链模式的优缺点
责任链模式简单认识
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. ---- 《设计模式》GoF
中文意思为:
通过给多个对象处理请求的机会,避免请求的发送方与其接收方耦合。将接收对象串起来,并沿着链传递请求,直到有一个对象处理它。
笔者的将其理解为:
现在有一条责任链(其中包含着各种接收对象,也可以理解为处理器,其具有处理请求的方法)。发送方对责任链发送请求,责任链中的对象A接收到请求后,若其能处理该请求,则处理,否则就向下一个对象传递请求,直到有一个对象能对其进行处理。整个过程形成一条链。
此外,责任链模式还有另一种实现方式,即
请求进入责任链,对象A接收到请求后,若需要处理,则处理,处理后传递给下一个对象;若不需要处理,则直接传递给下一个对象。也就是说,其最终都会将该对象传递给链上的下一个对象,以此类推,直到最后一个对象处理后,方结束。此变体中的请求会被责任链中的每个处理器(对象)处理。
责任链模式的简单应用
这两种责任链的实现方法
以下实现代码参考自王争先生在极客时间上的《设计模式之美》所展示的代码片段。我在其中注释部分加入了自己的理解、总结。
第一种责任链(即处理后就返回)
此责任链的实现方法有两种,分别是数组实现和链表实现。
-
数组实现
数组实现的大致模板:
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/** * 处理者接口,定义了处理者的行为 */ interface IHandler { boolean handle(); } /** * 处理者A */ class HandlerA implements IHandler { @Override public boolean handle() { boolean status = true; // 此处省略处理任务的方法…… // 如果任务被处理了,就令status为true;否则令其为false System.out.println("[HandlerA]: status is " + status); return status; } } /** * 处理者B */ class HandlerB implements IHandler { @Override public boolean handle() { boolean status = true; // 此处省略处理任务的方法…… // 如果任务被处理了,就令status为true;否则令其为false System.out.println("[HandlerB]: status is " + status); return status; } } /** * 责任链 */ class HandlerChain { // 责任链的数组存储对象 private List<IHandler> handlerList = new ArrayList<>(); // 向数组中添加handler的方法,添加成功返回true,反之为false public boolean addHandler(IHandler handler) { return this.handlerList.add(handler); } // 责任链调用处理者去处理请求 public void handle() { // 遍历责任链上的处理者 for (IHandler handler : handlerList) { boolean status = handler.handle(); // 如果处理者返回的是true,就说明已经处理请求了,可以退出遍历了 // 反之,继续遍历,直到被处理 if (status == true) { break; } } } } /** * 基于数组实现的责任链(处理后就停止的责任链) */ public class Demo { public static void main(String[] args) { HandlerChain handlerChain = new HandlerChain(); handlerChain.addHandler(new HandlerA()); handlerChain.addHandler(new HandlerB()); handlerChain.handle(); } }
输出结果为:
可见,HandleA处理了请求后,就不再往后传递请求了。
-
链表实现
链表实现的大致模板:
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101/** * 处理者抽象类,定义了处理者的行为 */ abstract class IHandler { // 下一个处理者 protected IHandler nextHandler; // 子类需要实现的处理方法 protected abstract boolean doHandle(); // 设置下一个处理者 public void setNextHandler(IHandler nextHandler) { this.nextHandler = nextHandler; } // 获取下一个处理者 public IHandler getNextHandler() { return this.nextHandler; } // 父类调用子类的处理方法判断是否向后传递请求 public final void handle() { boolean status = doHandle(); if ((!status) && (this.nextHandler != null)) { this.nextHandler.handle(); } } } /** * 处理者A */ class HandlerA extends IHandler { @Override public boolean doHandle() { boolean status = false; // 此处省略处理任务的方法…… // 如果任务被处理了,就令status为true;否则令其为false System.out.println("[HandlerA]: status is " + status); return status; } } /** * 处理者B */ class HandlerB extends IHandler { @Override public boolean doHandle() { boolean status = true; // 此处省略处理任务的方法…… // 如果任务被处理了,就令status为true;否则令其为false System.out.println("[HandlerB]: status is " + status); return status; } } /** * 责任链 */ class HandlerChain { // 责任链的头结点 private IHandler headHandler; // 责任链的尾结点 private IHandler tailHandler; // 向责任链中添加处理者 public void addHandler(IHandler handler) { // 把处理者的下一个结点设为空 handler.setNextHandler(null); // 如果头结点为空,说明责任链现在没有任何处理者,此时把头结点和尾结点都设置为函数传入的IHandler实例 if (this.headHandler == null) { this.headHandler = handler; this.tailHandler = handler; return; // 设置好后就返回,因为后面要给head非空时的情况赋值 } // headHandler非空时,把传进来的结点加入到链表尾部 this.tailHandler.setNextHandler(handler); this.tailHandler = handler; } // 责任链调用处理者去处理请求 public void handle() { if (this.headHandler != null) { this.headHandler.handle(); } } } /** * 基于链表实现的责任链(处理后就停止的责任链) */ public class Demo { public static void main(String[] args) { HandlerChain handlerChain = new HandlerChain(); handlerChain.addHandler(new HandlerA()); handlerChain.addHandler(new HandlerB()); handlerChain.handle(); } }
输出结果:
第二种责任链(一直往后传递)
此责任链的实现方法也是两种,即数组、链表实现。
-
数组实现
数组实现的大致模板:
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/** * 处理者接口,定义了处理者的行为 */ interface IHandler { // 实现类的处理方法 void handle(); } /** * 处理者A */ class HandlerA implements IHandler { @Override public void handle() { // 此处省略处理任务的方法… System.out.println("[HandlerA]: handle()"); } } /** * 处理者B */ class HandlerB implements IHandler { @Override public void handle() { // 此处省略处理任务的方法…… System.out.println("[HandlerB]: handle()"); } } /** * 责任链 */ class HandlerChain { // 责任链的存储对象 List<IHandler> handlerList = new ArrayList<>(); // 向责任链中添加处理者 public HandlerChain addHandler(IHandler handler) { handlerList.add(handler); return this; } // 责任链调用处理者去处理请求 public void handle() { for (IHandler handler : handlerList) { handler.handle(); } } } /** * 基于数组实现的责任链(处理后就停止的责任链) */ public class Demo { public static void main(String[] args) { HandlerChain handlerChain = new HandlerChain(); IHandler handlerA = new HandlerA(); IHandler handlerB = new HandlerB(); handlerChain.addHandler(handlerA).addHandler(handlerB); handlerChain.handle(); } }
输出结果:
-
链表实现
链表实现的大致模板:
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97/** * 处理者抽象类,定义了处理者的行为 */ abstract class IHandler { // 下一个处理者 protected IHandler nextHandler; // 子类需要实现的处理方法 protected abstract void doHandle(); // 设置下一个处理者 public void setNextHandler(IHandler nextHandler) { this.nextHandler = nextHandler; } // 获取下一个处理者 public IHandler getNextHandler() { return this.nextHandler; } // 父类调用子类的处理方法并向后请求 public final void handle() { doHandle(); // 与前一种责任链所不同的是,这里不需要通过前面是否处理判断是否传递,而是一直传递 if (this.nextHandler != null) { System.out.println("[IHandler]-nextHandler: " + this.nextHandler.getClass()); this.nextHandler.handle(); } } } /** * 处理者A */ class HandlerA extends IHandler { @Override public void doHandle() { // 此处省略处理任务的方法… System.out.println("[HandlerA]: doHandler()"); } } /** * 处理者B */ class HandlerB extends IHandler { @Override public void doHandle() { // 此处省略处理任务的方法…… System.out.println("[HandlerB]: doHandler()"); } } /** * 责任链 */ class HandlerChain { // 责任链的头结点 private IHandler headHandler; // 责任链的尾结点 private IHandler tailHandler; // 向责任链中添加处理者 public void addHandler(IHandler handler) { // 把处理者的下一个结点设为空 handler.setNextHandler(null); // 如果头结点为空,说明责任链现在没有任何处理者,此时把头结点和尾结点都设置为函数传入的IHandler实例 if (this.headHandler == null) { this.headHandler = handler; this.tailHandler = handler; return; // 设置好后就返回,因为后面要给head非空时的情况赋值 } // headHandler非空时,把传进来的结点加入到链表尾部 this.tailHandler.setNextHandler(handler); this.tailHandler = handler; } // 责任链调用处理者去处理请求 public void handle() { if (this.headHandler != null) { this.headHandler.handle(); } } } /** * 基于链表实现的责任链(处理后就停止的责任链) */ public class Demo { public static void main(String[] args) { HandlerChain handlerChain = new HandlerChain(); handlerChain.addHandler(new HandlerA()); handlerChain.addHandler(new HandlerB()); handlerChain.handle(); } }
输出结果:
可以看到,HandlerA在处理了请求后,又传递给了HandlerB,HandlerB也对请求进行了处理。
责任链的一些应用
####一个小案例
假设有一场景如下:我们需要对用户的登录请求进行登陆前的数据校验、登录表单的数据校验、权限数据的校验。
在这样的场景中,我们通常会这样去实现(模拟实现,省略了部分操作、代码):
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
73public class Demo { public boolean login(User user) { String userName = user.getUserName(); String password = user.getPassword(); // 非空校验(数据校验部分) if (StringUtils.isEmpty(userName) && StringUtils.isEmpty(password)) { System.out.println("数据校验不通过!"); return false; } System.out.println("数据校验通过!"); // 用户名、密码校验,模拟验证 if (userName != "xingzhi" && password != "987") { System.out.println("用户名或密码错误!"); return false; } System.out.println("用户名、密码校验通过!"); user.setRoleName("visitor"); // 用户角色校验 if (user.getRoleName() != "admin") { System.out.println("无权限登录!"); return false; } System.out.println("权限验证通过"); return true; } // 模拟登录接口调用 public static void main(String[] args) { Demo demo = new Demo(); User user = new User().setUserName("xingzhi").setPassword("987"); if (demo.login(user)) { System.out.println("登陆成功!"); } else { System.out.println("登陆失败!"); } } } // 模拟一个用户类 class User { private String userName; private String password; private String roleName; public String getUserName() { return userName; } public User setUserName(String userName) { this.userName = userName; return this; } public String getPassword() { return password; } public User setPassword(String password) { this.password = password; return this; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } }
输出结果如下:
这样确实把需求实现了,但是
根据这一场景,责任链模式是一个很好的选择。因为进行完一个校验后还需要后续的校验,所以我们选择使用第二种责任链的链表实现方式来完成需求(需要注意的是,当某一处理者不通过时,就不往下传递了,所以我在Ihandler接口类中新增了handlerStatus属性用来记录处理者的处理状态)。代码如下:(但我感觉我这个案例可能不太好…)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181/** 处理者父类 */ abstract class abstractHandler { // 下一个处理者 protected abstractHandler nextHandler; protected boolean handlerStatus; // 子类需要实现的处理方法 protected abstract boolean doHandle(User user); // 设置下一个处理者 public void setNextHandler(abstractHandler nextHandler) { this.nextHandler = nextHandler; } // 获取下一个处理者 public abstractHandler getNextHandler() { return this.nextHandler; } // 父类调用子类的处理方法并向后请求 public final boolean handle(User user) { handlerStatus = doHandle(user); if (!handlerStatus) return false; // 与前一种责任链所不同的是,这里不需要通过前面是否处理判断是否传递,而是一直传递 if (this.nextHandler != null) { System.out.println("[IHandler]-nextHandler: " + this.nextHandler.getClass()); this.nextHandler.handle(user); } return true; } } /** * 数据校验处理者 */ class ValidateHandler extends abstractHandler { @Override public boolean doHandle(User user) { System.out.println("[ValidateHandler]: doHandler()"); // 如果用户名和密码不为空,则进行处理 if (!StringUtils.isEmpty(user.getUserName()) && !StringUtils.isEmpty(user.getPassword())) { System.out.println("数据校验成功!"); return true; } else { System.out.println("数据格式不通过!"); return false; } } } /** * 身份校验处理者 */ class AuthenticationHandler extends abstractHandler { @Override public boolean doHandle(User user) { System.out.println("[AuthenticationHandler]: doHandler()"); if ("xingzhi".equals(user.getUserName()) && "987".equals(user.getPassword())) { user.setRoleName("admin"); System.out.println("身份验证通过!"); return true; } else { System.out.println("身份验证不通过!"); return false; } } } /** 角色校验处理者 */ class RoleHandler extends abstractHandler { @Override public boolean doHandle(User user) { System.out.println("[RoleHandler]: doHandler()"); if ("admin".equals(user.getRoleName())) { System.out.println("橘色校验通过!"); return true; } else { System.out.println("角色校验不通过!"); return false; } } } /** * 责任链 */ class LoginHandlerChain { // 责任链的头结点 private abstractHandler headHandler; // 责任链的尾结点 private abstractHandler tailHandler; // 向责任链中添加处理者 public LoginHandlerChain addHandler(abstractHandler handler) { // 把处理者的下一个结点设为空 handler.setNextHandler(null); // 如果头结点为空,说明责任链现在没有任何处理者,此时把头结点和尾结点都设置为函数传入的IHandler实例 if (this.headHandler == null) { this.headHandler = handler; this.tailHandler = handler; return this; // 设置好后就返回,因为后面要给head非空时的情况赋值 } // headHandler非空时,把传进来的结点加入到链表尾部 this.tailHandler.setNextHandler(handler); this.tailHandler = handler; return this; } // 责任链调用处理者去处理请求 public boolean handle(User user) { if (this.headHandler != null) { return this.headHandler.handle(user); } return false; } } // 模拟一个用户类 class User { private String userName; private String password; private String roleName; private String Permission; public String getUserName() { return userName; } public User setUserName(String userName) { this.userName = userName; return this; } public String getPassword() { return password; } public User setPassword(String password) { this.password = password; return this; } public String getRoleName() { return roleName; } public User setRoleName(String roleName) { this.roleName = roleName; return this; } public String getPermission() { return Permission; } public User setPermission(String permission) { Permission = permission; return this; } } /** * 基于链表实现的责任链(处理后就停止的责任链) */ public class Demo { public static void main(String[] args) { User user = new User() .setUserName("xingzhi") .setPassword("987"); LoginHandlerChain loginHandlerChain = new LoginHandlerChain() .addHandler(new ValidateHandler()) .addHandler(new AuthenticationHandler()) .addHandler(new RoleHandler()); if (loginHandlerChain.handle(user)) { System.out.println("登陆成功!欢迎您:" + user.getUserName()); } else { System.out.println("登陆失败!"); }; } }
运行结果如图:
在这个场景中使用责任链模式就可以满足开闭原则,提高代码的扩展性。
比如,现在需要在角色认证后进行权限认证,这时我们只需要增加一个权限验证类就行了,但是我这个User类还得改改…所以我这个案例举得不太好(有点又臭又长了)…仅供参考…哈哈…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/** 权限校验处理者 */ class PermissionHandler extends abstractHandler { @Override public boolean doHandle(User user) { System.out.println("[PermissionHandler]: doHandler()"); if ("menu:add".equals(user.getPermission())) { System.out.println("权限校验通过!"); return true; } else { System.out.println("权限校验不通过!"); return false; } } }
责任链模式在源码中的体现
在看过了我的糟糕的案例后,我们来看看大师的作品,源码中的责任链模式:
1
2
3
4/** * 先留个坑...有时间了来填... */
责任链模式的优缺点
最后,总结下责任链模式的优缺点。
优点
- 将请求的发送者和接收者解耦。
- 简化对象,减少代码的复杂性。(处理者不需要知道责任链的内部构造以及如何处理的)
- 满足开闭原则,提高代码的扩展性。(动态地新增或删除责任)
缺点
- 不容易观察运行时的特征,出现问题不好排查。(如果某一节点出现问题,则容易造成系统崩溃)
- 并不一定保证请求一定会执行。(责任链过长时,请求没被处理或者处理时间过长,会影响整体性能)
最后
以上就是友好手机最近收集整理的关于设计模式学习总结:责任链模式的全部内容,更多相关设计模式学习总结内容请搜索靠谱客的其他文章。
发表评论 取消回复