责任链模式ChainofResponsibility

简单实现--实现链式调用以及调用链中断

interface Filter {
    boolean doFilter(Msg m);
}


class HTMLFilter implements Filter {
    @Override
    public boolean doFilter(Msg m) {
        String r = m.getMsg();
        r = r.replace('<', '[');
        r = r.replace('>', ']');
        m.setMsg(r);
        return true;
    }
}

// ... 其他具体的过滤器实现类

调用链也实现Filter接口,是为了可以两个链子连起来。也就是说把后面的链子当做过滤器的List的最后一个元素。利用了多态,都实现了doFilter,但是具体的过滤器是具体的处理,FilterChain 的 doFilter是为了开始调用自己的链子注意此时上一个还在栈里面,有点类似递归。

  • add(Filter f)  返回 FilterChain ,是为了链式调用,注意add方法是只有FilterChain 有的,其他实现了Filter 的具体过滤器是没有这个方法的。
  • doFilter(Msg m) :返回boolean 为了决定是否继续往下调用链子上面后面的调用器
class FilterChain implements Filter {
    private List<Filter> filters = new ArrayList<>();

    public FilterChain add(Filter f) {
        filters.add(f);
        return this;
    }

    public boolean doFilter(Msg m) {
        for(Filter f : filters) {
            // 精髓,利用返回的boolean决定还是否往下传递
            if(!f.doFilter(m)) return false;
        }

        return true;
    }
}

调用案例

FilterChain fc = new FilterChain();
fc.add(new HTMLFilter()).add(new SensitiveFilter());

FilterChain fc2 = new FilterChain();
fc2.add(new FaceFilter()).add(new URLFilter());

// 拼接前后两个调用链
fc.add(fc2);

fc.doFilter(msg);

Servlet的Filter

和上面直接在FilterChain里面遍历所有的Filter,调用doFilter不一样,为了实现req是abc顺序,resp是cba顺序,这里使用利用了递归的思想,不在FilterChain设置for循环,而是每一个具体的Filter都去调用FilterChain的doFilter,让FilterChain去调用下一个Filter,返回的时候其实就是递归返回,再执行后面的语句,也就是对resp操作,就相当于是栈,毕竟栈就是递归的具象。所以返回的时候顺序就反过来了。

  • 具体的过滤器的doFilter实现:<font style="color:#cc7832;">public boolean </font>``<font style="color:#ffc66d;">doFilter</font>``_(_``Request request``<font style="color:#cc7832;">, </font>``Response response``<font style="color:#cc7832;">, </font>``FilterChain chain``_)_
    • **内部自己处理之后调用Filter的doFilter方法来调用下一个filter **
  • FilterChain的doFilter实现:public void doFilter(Request request, Response response)
    • 内部直接调用链子里的下一个Filter
    • 借助对象变量 index 标志当前运行到哪一个过滤器了
package com.deltaqin.designPattern.d10_chainOfResponsibility.servletFilter;

import java.util.ArrayList;
import java.util.List;

/**
 * @author deltaqin
 * @date 2021/3/27 12:39 下午
 */
public class ServletFilter {
    public static void main(String[] args) {
        Request request = new Request();
        request.str = "大家好:),<script>,deltaqin ,大家都是996 ";
        Response response = new Response();
        response.str = "response";

        FilterChain chain = new FilterChain();
        chain.add(new HTMLFilter()).add(new SensitiveFilter());
        chain.doFilter(request, response);
        System.out.println(request.str);
        System.out.println(response.str);

    }
}

interface Filter {
    void doFilter(Request request, Response response, FilterChain chain);
}

class HTMLFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        request.str = request.str.replaceAll("<", "[").replaceAll(">", "]") + "HTMLFilter()";
        chain.doFilter(request, response);
        response.str += "--HTMLFilter()";

    }
}

class Request {
    String str;
}

class Response {
    String str;
}

class SensitiveFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        request.str = request.str.replaceAll("996", "955") + " SensitiveFilter()";
        chain.doFilter(request, response);
        response.str += "--SensitiveFilter()";

    }
}

class FilterChain {
    List<Filter> filters = new ArrayList<>();
    int index = 0;

    public FilterChain add(Filter f) {
        filters.add(f);
        return this;
    }

    public void doFilter(Request request, Response response) {
        // 这里相当于是递归结束的条件,调用链里面的所有的需要调用的都调用过了,就返回
        if(index == filters.size())
            return;

        // 否则继续调用下一个Filter
        Filter f = filters.get(index++);
        f.doFilter(request, response, this);
    }
}

Tomcat中的责任链模式

简单的上一个链条调用下一个链条

HTTP 协议可简单分为请求头和请求体两部分,Tomcat 在收到一条完整的 HTTP 请求时,也会将其分为请求头和请求体两部分进行处理的。

不过在真正的 Tomcat 实现中,会将 HTTP 请求细分为更多部分,然后逐步进行处理,整个 Tomcat 代码处理 HTTP 请求的实现也更为复杂。

试想一下,Tomcat 将处理请求的各个细节的实现代码都堆到一个类中,那这个类的代码会非常长,维护起来也非常痛苦,可以说是“牵一发而动全身”。如果 HTTP 请求升级,那就需要修改这个臃肿的类,显然是不符合“开放-封闭”原则的。

为了实现像 HTTP 这种多部分构成的协议的处理逻辑,我们可以使用责任链模式来划分协议中各个部分的处理逻辑,将那些臃肿实现类拆分成多个 Handler(或 Interceptor)处理器,在每个 Handler(或 Interceptor)处理器中只专注于 HTTP 协议中一部分数据的处理。我们可以开发多个 Handler 处理器,然后按照业务需求将多个 Handler 对象组合成一个链条,从而实现整个 HTTP 请求的处理。

这样做既可以将复杂、臃肿的逻辑拆分,便于维护,又能将不同的 Handler 处理器分配给不同的程序员开发,提高开发效率。

在责任链模式中,Handler 处理器会持有对下一个 Handler 处理器的引用,也就是说当一个 Handler 处理器完成对关注部分的处理之后,会将请求通过这个引用传递给下一个 Handler 处理器,如此往复,直到整个责任链中全部的 Handler 处理器完成处理。

1623034790443-1d0cd73e-d15a-4880-888d-0c4c29fe778a.png

假设我们自定义了一套协议,其请求中包含 A、B、C 三个核心部分,业务系统使用 Handler A、Handler B、Handler C 三个处理器来处理这三部分的数据。如果业务变化导致我们的自定义协议也发生了变化,协议中的数据变成了 A、C、D 这三部分,那么我们只需要动态调整构成责任链的 Handler 处理器即可,最新的责任链变为 Handler A、Handler C、Handler D。如下图所示:

1623034842803-d72f45e2-9694-44dd-a27d-90f88b336b15.png

由此可见,责任链模式可以帮助我们复用 Handler 处理器的实现逻辑,提高系统的可维护性和灵活性,很好地符合了“开放-封闭”原则。

posted on 2025-10-14 23:09  chuchengzhi  阅读(7)  评论(0)    收藏  举报

导航

杭州技术博主,专注分享云计算领域实战经验、技术教程与行业洞察, 打造聚焦云计算技术的垂直博客,助力开发者快速掌握云服务核心能力。

褚成志 云计算 技术博客