【设计模式】通俗易懂版责任链模式
作者:行百里er
博客:https://chendapeng.cn (opens new window)
提示
这里是 行百里er 的博客:行百里者半九十,凡事善始善终,吾将上下而求索!
# 引入
汽车生产过程中,必然要对汽车的各个部件,比如发动机、变速箱、车身等等进行严格的质量检查,对不合格的部件进行过滤。
# 过滤检查汽车部件
一般情况下,我们这样写就能实现了:
public class Client {
public static void main(String[] args) {
Client client = new Client();
Request req = new Request();
req.setReqMsg("检查发动机,变速箱,车身有没有问题");
if (req.getReqMsg().contains("车身")) {
client.doCheckCarbody();
}
if (req.getReqMsg().contains("发动机")) {
client.doCheckEngine();
}
if (req.getReqMsg().contains("变速箱")) {
client.doCheckGearbox();
}
if (req.getReqMsg().contains("xxx")) {
// do something
}
}
public void doCheckEngine () {
System.out.println("------检查了发动机------");
}
public void doCheckCarbody () {
System.out.println("------检查了车身-------");
}
public void doCheckGearbox () {
System.out.println("------检查了变速箱-----");
}
}
class Request {
private String reqMsg;
public String getReqMsg() {
return reqMsg;
}
public void setReqMsg(String reqMsg) {
this.reqMsg = reqMsg;
}
}
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
but,看到
if (req.getReqMsg().contains("xxx")) {
// do something
}
2
3
这个了吗?这意味着检查的东西增多,if
语句也就变多了(好熟悉的代码,哈哈)
# 如何干掉臃肿的if
,优雅的执行汽车部件检查?
针对上面的代码,如果哪天哪个部件获得免检了,不需要检查了,还得去掉某一个if
分支,这时候你就恨不得把所有代码都重构了。。。
面向对象有一个词叫 封装变化 ,也就是说 哪部分要变化,就封装哪部分 ,我们可以对处理汽车部件的部分进行封装。
代码如下:
public class Client {
public static void main(String[] args) {
Request req = new Request();
req.setReqMsg("检查发动机,变速箱,车身有没有问题");
List<Filter> filters = new ArrayList<>();
filters.add(new CarbodyFilter());
filters.add(new GearboxFilter());
filters.add(new EngineFilter());
for (Filter f : filters) {
f.doFilter(req);
}
}
}
class Request {
private String reqMsg;
public String getReqMsg() {
return reqMsg;
}
public void setReqMsg(String reqMsg) {
this.reqMsg = reqMsg;
}
}
interface Filter {
boolean doFilter(Request request);
}
class EngineFilter implements Filter {
@Override
public boolean doFilter(Request request) {
if (request.getReqMsg().contains("发动机")) {
System.out.println("------检查了发动机------");
}
return true;
}
}
class GearboxFilter implements Filter {
@Override
public boolean doFilter(Request request) {
if (request.getReqMsg().contains("变速箱")) {
System.out.println("------检查了变速箱------");
}
return true;
}
}
class CarbodyFilter implements Filter {
@Override
public boolean doFilter(Request request) {
if (request.getReqMsg().contains("车身")) {
System.out.println("------检查了车身------");
}
return true;
}
}
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
这样一来,如果要对哪个部件进行检查,只需要向
List<Filter> filters = new ArrayList<>();
filters
里添加Filter
就行了,这个代码是不是稍微有那么点意思了?
# 没有最优雅,只有更优雅
上个版本的代码,仍需要在 Client
里面的 List<Filter>
里添加需要执行的 Filter
,还是差点意思。
我们来看一下上面描述的场景:
是不是每个 Filter
各司其职,只要把每个 Filter
串起来让他们内部去执行就好了!
那我们来写一个 FilterChain
来把他们串起来:
class FilterChain implements Filter {
List<Filter> filters = new ArrayList<>();
//比较骚的写法,这样可以链式调用
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
//一般写法
// public void add(Filter filter) {
// filters.add(filter);
// }
@Override
public boolean doFilter(Request request) {
for (Filter f : filters) {
//任何一环检查出了问题,均不往下检查
if (!f.doFilter(request)) {
return false;
}
}
return true;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
这里提一下FilterChain
中的add
方法,先看一般写法:
public void add(Filter filter) {
filters.add(filter);
}
2
3
然后调用就得这样来搞:
FilterChain chain = new FilterChain();
chain.add(new EngineFilter());
chain.add(new GearboxFilter());
chain.add(new CarbodyFilter());
chain.doFilter(req);
2
3
4
5
有一种比较骚的写法:
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
2
3
4
调用:
FilterChain chain = new FilterChain();
chain.add(new EngineFilter())
.add(new GearboxFilter())
.add(new CarbodyFilter())
.doFilter(req);
2
3
4
5
咦?我在xx源码见过这个写法!感觉瞬间提升了几个档次。
上面的 FilterChain
版本,其实就是 责任链模式 !!!
# 似曾相识的FilterChain
没错,如果你开发过Java Web程序,你一定见过这个东西。
比如 Servlet
的 Filter
, Struts
的 Interceptor
, Spring MVC
的 HandlerInterceptor
。它们本质上都是过滤器或者叫拦截器。
我用刚才的场景
模拟了一下Filter
和FilterChain
:
public class Client {
public static void main(String[] args) {
Request request = new Request();
request.reqMsg = "检查发动机,变速箱,车身有没有问题";
Response response = new Response();
response.respMsg = "-------response:";
FilterChain chain = new FilterChain();
chain.add(new EngineFilter()).add(new GearboxFilter()).add(new CarbodyFilter());
chain.doFilter(request, response);
System.out.println(response.respMsg);
}
}
class Request {
String reqMsg;
}
class Response {
String respMsg;
}
interface Filter {
void doFilter(Request request, Response response, FilterChain chain);
}
class EngineFilter implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
//先处理request请求
if (request.reqMsg.contains("发动机")) {
System.out.println("------EngineFilter 检查了发动机------");
}
//通过链条传递处理下一个request
chain.doFilter(request, response);
//处理response
response.respMsg += "---执行了EngineFilter过滤器---";
}
}
class GearboxFilter implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
if (request.reqMsg.contains("变速箱")) {
System.out.println("------GearboxFilter 检查了变速箱------");
}
//通过链条传递处理下一个request
chain.doFilter(request, response);
//处理response
response.respMsg += "---执行了GearboxFilter过滤器---";
}
}
class CarbodyFilter implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
if (request.reqMsg.contains("车身")) {
System.out.println("------CarbodyFilter 检查了车身------");
}
//通过链条传递处理下一个request
chain.doFilter(request, response);
//处理response
response.respMsg += "---执行了CarbodyFilter过滤器---";
}
}
class FilterChain {
List<Filter> filters = new ArrayList<>();
int filterIndex = 0;
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
public void doFilter(Request request, Response response) {
//如果request链条执行完了,就不往下传递了
if (filterIndex == filters.size()) {
return;
}
Filter f = filters.get(filterIndex);
filterIndex++;
f.doFilter(request, response, this);
}
}
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
捋一捋:
FilterChain
里面定义了一个 filterIndex
来控制链条顺序执行,并且在每个filter的doFilter里
- 先处理request
- 调用chain.doFilter(request, response)传递链条
- 处理response
看下执行结果:
这些框架的过滤器、拦截器使用的也是 责任链模式 。
# 小结
- 责任链模式 (Chain of Responsibility)是一种 处理请求 的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递。
- 责任链模式在添加新的处理类或者排列处理请求的顺序上非常容易。
- 拦截、预处理请求等场景下经常会用到责任链模式。
暗示自己:好好学习设计模式,咱也能写出优秀的代码!!!
以上。
首发公众号 行百里er ,欢迎老铁们关注阅读指正。