行百里er 行百里er
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)

行百里er

Java程序员一枚
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)
  • 【设计模式】各个击破单例模式的8种写法
  • 【设计模式】策略模式之“这不就是if-else吗”
  • 【设计模式】工厂系列-FactoryMethod,AbstractFactory,Spring IOC
  • 【设计模式】只需体验三分钟,你就会跟我一样了解Facade和Mediator模式
  • 【设计模式】代理模式那些事儿:静态代理,动态代理,JDK的动态代理,cglib,Spring AOP
  • 【设计模式】通俗易懂版责任链模式
    • 引入
    • 过滤检查汽车部件
    • 如何干掉臃肿的if,优雅的执行汽车部件检查?
    • 没有最优雅,只有更优雅
    • 似曾相识的FilterChain
    • 小结
  • 【设计模式】模板模式,学会它咱也写出优雅健壮的代码!
  • 【设计模式】好玩的原型模式:Prototype
  • 【设计模式】1分钟整明白什么是Builder建造者模式
  • 设计模式
行百里er
2020-08-14
目录

【设计模式】通俗易懂版责任链模式

作者:行百里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;
    }
}
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

but,看到

if (req.getReqMsg().contains("xxx")) {
    // do something
}
1
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;
    }
}
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

这样一来,如果要对哪个部件进行检查,只需要向

List<Filter> filters = new ArrayList<>();
1

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;
    }
}
1
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);
}
1
2
3

然后调用就得这样来搞:

FilterChain chain = new FilterChain();
chain.add(new EngineFilter());
chain.add(new GearboxFilter());
chain.add(new CarbodyFilter());
chain.doFilter(req);
1
2
3
4
5

有一种比较骚的写法:

public FilterChain add(Filter filter) {
    filters.add(filter);
    return this;
}
1
2
3
4

调用:

FilterChain chain = new FilterChain();
chain.add(new EngineFilter())
        .add(new GearboxFilter())
        .add(new CarbodyFilter())
        .doFilter(req);
1
2
3
4
5

咦?我在xx源码见过这个写法!感觉瞬间提升了几个档次。

上面的 FilterChain 版本,其实就是 责任链模式 !!!

# 似曾相识的FilterChain

没错,如果你开发过Java Web程序,你一定见过这个东西。

比如 Servlet 的 Filter , Struts 的 Interceptor , Spring MVC 的 HandlerInterceptor 。它们本质上都是过滤器或者叫拦截器。

JavaEE Filter

我用刚才的场景

模拟了一下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);
    }
}
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

捋一捋:

FilterChain 里面定义了一个 filterIndex 来控制链条顺序执行,并且在每个filter的doFilter里

  1. 先处理request
  2. 调用chain.doFilter(request, response)传递链条
  3. 处理response

看下执行结果:

这些框架的过滤器、拦截器使用的也是 责任链模式 。

# 小结

  • 责任链模式 (Chain of Responsibility)是一种 处理请求 的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递。
  • 责任链模式在添加新的处理类或者排列处理请求的顺序上非常容易。
  • 拦截、预处理请求等场景下经常会用到责任链模式。

暗示自己:好好学习设计模式,咱也能写出优秀的代码!!!

以上。


首发公众号 行百里er ,欢迎老铁们关注阅读指正。

#设计模式
上次更新: 2022/10/06, 18:00:06
【设计模式】代理模式那些事儿:静态代理,动态代理,JDK的动态代理,cglib,Spring AOP
【设计模式】模板模式,学会它咱也写出优雅健壮的代码!

← 【设计模式】代理模式那些事儿:静态代理,动态代理,JDK的动态代理,cglib,Spring AOP 【设计模式】模板模式,学会它咱也写出优雅健壮的代码!→

最近更新
01
重要数据不能丢!MySQL数据库定期备份保驾护航!
05-22
02
分布式事务解决方案之 Seata(二):Seata AT 模式
09-09
03
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
09-05
更多文章>
Theme by Vdoing | Copyright © 2020-2023 行百里er | MIT License | 豫ICP备2022020385号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式