This is the "chain of responsibility model"?

Preface


Only a bald head can become stronger.

The text has been included in my GitHub Featured Article, welcome to Star : https://github.com/ZhongFuCheng3y/3y

Recently, when I was looking at the project code, I found the "Chain of Responsibility Model", so I wanted to spend some time to write about what is the Chain of Responsibility Model.

I don’t know how everyone learns design patterns. Generally, I only learn them when I use them or when I get in touch. Otherwise, I feel that it is easy to forget after learning, and I can't understand why design patterns are used (because there is no real scene for me to use).

I have updated a few articles on design patterns before, and I think the writing is "okay", and interested students can go to my GitHub and search for " design patterns " by keyword to find the corresponding articles.

image.pngimage.png

1. What is the chain of responsibility model?

Before talking about the chain of responsibility model, let's talk about " filters " first.

I believe everyone must have learned the filter. We will learn it when we first learn Servlet Filter. When we learn Struts2, we will learn Interceptor. When we learn SpringMVC, we will learn HandlerInterceptor.

But no matter which framework we learn, we found that it actually does Filtersuch a thing in the end. To put it bluntly:

  • Put all the filters in the FilterChain and execute each filter in turn.

I have talked about Filter, HandlerInterceptor, and Interceptor in my GitHub. If you want to review, you may go in and search for the keywords " filter " " Struts2 " " SpringMVC "

image.png Why do we need to talk about "filters" in the chain of responsibility model? I'll talk about it later, don't worry.

1.1 Kill Ao Bing and eggs

For example: Imagine our normal request as a pile of sundries, with rice beans, eggs, Ao Bing doll toys and other sundries inside. image.pngNow what we want is rice beans , eggs and Ao Bing toys are filtered out. So we can make two filters to filter out Ao Bing toys and eggs.

In the fastest way, we can write ifto deal with this requirement, the following code.

A request, we use Requestobjects to represent:

public class Request {
    // 请求的数据
    private String data;

    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

For the request, we must have an interface to handle the request, we use Handlerto indicate:

public class Handler {

    public void handlerRequest(Request request) {

        // 得到请求的数据
        String data = request.getData();

        if (data.contains("鸡蛋")) {
            filterEgg(data);
        }
        if (data.contains("敖丙工具")) {
            filterAoBing(data);
        }
        // 我到这里就能拿到米豆了。
    }

    private void filterAoBing(String data) {
        //doSomething
    }

    private void filterEgg(String data) {
        //doSomething
    }
}

You don't know if you are familiar with the above code. Anyway, I am very familiar with it. Many times I write code like this (a lot of codes in reality are like this).

1.2 How to kill Ao Bing and eggs more gracefully?

In a certain year and certain month, the product came and told me that it needed to add a new type of "cabbage" to be filtered

In a certain month and year, the product came to tell me that a new type of "chicken leg" that I want to filter needs to be added

In a certain month and year, the product came and told me that a new type of "chicken head" to be filtered should be added

So our Handler processing may "expand", may it be?

public class Handler {

    public void handlerRequest(Request request) {

        // 得到请求的数据
        String data = request.getData();

        if (data.contains("鸡蛋")) {
            filterEgg(data);
        }
        if (data.contains("敖丙工具")) {
            filterAoBing(data);
        }
        if (data.contains("白菜")) {
            filterBaiCai(data);
        }
        if (data.contains("鸡头")) {
            filterJiTou(data);
        }
        if (data.contains("鸡腿")) {
            filterJiTui(data);
        }
        // 我到这里就能拿到米豆了。
    }

    private void filterJiTou(String data) {
        //doSomething
    }

    private void filterJiTui(String data) {
        //doSomething
    }

    private void filterAoBing(String data) {
        //doSomething
    }

    private void filterEgg(String data) {
        //doSomething
    }
}

Obviously, if the processing flow changes significantly (one of the processes needs to be added or deleted), then I need to change handlerRequestthe code every time , adding/modifying/deleting one ifand one processing method.

A more object-oriented way is like this: each processing method is abstracted into a class, and each class performs its own duties .

无论是过滤敖丙还是过滤鸡蛋还是过滤米豆,做的事都是过滤。我们就可以将其抽象成接口。于是我们就有一个接口,多个实现类

public interface Filter {
    // 过滤
    void doFilter(String data);
}

class FilterEgg implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterAoBing implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterBaiCai implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterJiTou implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

每个各司其职的Filter都有可能被执行,我们可以将其串成一条链,抽象一层对外只暴露一个方法来替代if。于是我们可以写出一个FilterChain

public class FilterChain {
    List<Filter> filters = new ArrayList<>();

    public FilterChain() {
        filters.add(new FilterEgg());
        filters.add(new FilterAoBing());
        filters.add(new FilterBaiCai());
        filters.add(new FilterJiTou());
    }
    public void processData(String data) {
        for (Filter filter : filters) {
            filter.doFilter(data);
        }
    }
}

改造过后,我们的Handler就长这个样子了:

public class Handler {
    public void handlerRequest(Request request) {
        // 得到请求的数据
        String data = request.getData();
        FilterChain filterChain = new FilterChain();
        // 处理数据
        filterChain.processData(data);
    }
}

如果我告诉你,这种的处理方式就是责任链模式,你会怎么想?

二、为什么责任链模式?

再来回顾一下,我做了些什么:

  1. 将处理的各个流程抽象为各个类(本来Handler里边有多个if方法)

  2. 将多个类用Chain链起来,暴露一个方法给Handler使用

  3. done

下面我画了一张对比图:image.png是不是很简单?说到底还是抽象了一层(将每个处理抽象为一个类而已)。image.png那为什么要这样干?如果我要增加一个处理流程,我是得新增一个处理类,然后在链上增加相对应的类。操作也的确如此。

这不麻烦吗?要便捷的话,我还不如直接增加一个if,一个处理方法来得方便呢。

用责任链模式的好处就是分工明确,解耦,容易维护

  • 将多个条件判定分散到各个的处理类上,相对于if else耦合性相对较低。

  • 增加一个具体的Handler处理类,不会影响到BaseHandler的代码

责任链模式的缺点:

  • 项目里边会有多个具体Handler类(因为每种处理都抽象为一个类,所以会有多个类)

  • 不好调试,初看代码时不好阅读。(对外只是一个doChain方法,而里边由多个处理类来组成,还得看相应的调用顺序)

三、再来聊聊责任链模式

我们从上面也可以看到责任链模式主要有以下特点:

  • 一个Handler接口,多个Handler处理类

  • 多个Handler处理类串起来形成一条链

有这两个特点我就称这些代码运用了责任链模式。在翻阅资料或者看书的时候,你可能会看到:“责任链和不纯责任链”

  • 纯:请求执行到某个具体的Handler,该Handler要么自行处理然后结束请求,要么不处理继续往下给别的Handler执行。

  • 不纯:请求执行到某个具体的Handler,该Handler自行处理了,继续往下给别的Handler执行。

还有就是将各个具体的Handler串成一条链,这里边的实现会有各式各样的:

  • 在我例子里是直接new出一个ArrayList,然后在构造方法里边代码手动add到ArrayList的

  • 有可能会在代码里边每个具体Handler都会记录自己下一个Handler是谁

  • 有可能将Handler的初始化放在XML上

  • ….//反正各种操作最终还是会将各个Handler串起来

其实不必要在意纯和不纯的责任链模式,我们学设计模式是为了学它的思想

四、看看JavaWeb的Filter

在文章最开头我就说了我们以前学过的Filter,其实Filter就是用了责任链模式。我们来简单看看代码:

我们在使用Filter过滤器的时候,要么在XML上配置<filter>,要么在代码上写上注解@WebFilter(filterName = "",urlPatterns = "")

这些配置都会在Web容器启动的时候被读取,读完这些配置,会将你写的Filter过滤器加到FilterChain里边:image.png我们可以看到Filter接口下有很多都实现了doFilterimage.pngJavaWeb的Filter实际用到的也是责任链模式。

最后

设计模式本身不是一件很复杂的东西,像门面模式,模板方法模式都非常容易理解。学完了会有一种感觉:“啊?就这?

重要的是学完能不能用到实际的工作中,这是非常难能可贵的。我们写代码按照自身的思维写if else是非常简单的,而设计模式往往需要绕一个圈才能把功能实现。

但是,合理运用设计模式的代码是非常好维护的。如果你懂设计模式,那代码会看起来非常清晰。如果你不懂设计模式,你就会感叹“这代码是真的骚阿”(这就是我…)。

好好学习,希望有朝一日,别人看到我的代码,在背后说「这人写的代码是真的骚,牛逼阿」。

参考资料:

  • 《设计模式之禅》

  • https://www.cnblogs.com/tanshaoshenghao/p/10741160.html



如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号Java3y

  • 获取海量视频资源

  • Get a beautiful mind map in Java

  • Get the Java learning route

  • Get common development tools

  • Jing Mei whole reason Hao the PDF e-book


Reply " 888 " under the official account to get it! !

image.png

Click one to watch it and share it with friends, it’s really important to me! !



Guess you like

Origin blog.51cto.com/15082392/2590095