设计模式 -(6)责任链模式(Chain Of Responsibility pattern)

本文介绍了一种常用的设计模式——责任链模式,通过实例演示如何利用该模式处理一系列校验任务,如黑名单校验和坏账校验等。此外,还探讨了如何使用责任链模式过滤字符串中的特定字符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计模式 -(6)责任链模式(Chain Of Responsibility pattern)

前言

之前做过一个这样的需求:在客户办理业务时对客户信息进行校验,如黑名单校验,坏账校验,如果校验失败则不允许客户继续办理业务。
针对这种情况,首先想到的便是直接在一个方法中完成所有的校验,比如:

public String check(){
    if(校验黑名单失败){
        return "客户在黑名单中!";
    }
    if(校验坏账失败){
        return "客户存在坏账没处理!";
    }
    return "校验成功!";
}

如果逻辑简单,代码较少,这样处理未尝不可,但是如果每个校验都有自己单独的逻辑,并且代码量较多,而且有时候需要按照不同的顺序来处理,比如先校验坏账后校验黑名单,那么就必须改动 check 中的代码来达到目的,显然这样不合适
而这种业务非常适合用责任链模式来处理,比如 黑名单 专门使用黑名单校验类来处理,坏账 专门使用坏账的校验类来处理,将这些校验对象放入一个校验数组(校验链)中,依次对客户信息进行不同的校验处理,后续如果有新的校验规则直接加入校验链中即可,并且校验链可以自由调整校验规则的顺序,这种方式明显比直接改 check 方法更加灵活

举例说明

举个过滤字符串中的英文字母,空格,html 标签的例子

定义过滤接口 StrFilter :

public interface StrFilter {
    String doFilter(String str);
}

过滤空格的类:

public class BlankFilter implements StrFilter{

    @Override
    public String doFilter(String str) {
        return  str.replaceAll("\\s+","");
    }

}

过滤英文字母的类:

public class EnglishLetterFilter implements StrFilter{

    @Override
    public String doFilter(String str) {
        return  str.replaceAll("[A-Za-z]","");
    }
}

过滤器链:

/**
 * 过滤器链
 * 过滤器链中的过滤器存放在 filterList(元素类型为 StrFilter) 中
 * addFilter 方法允许 一个 StrFilterChain 添加另外一个 StrFilterChain,因为 StrFilterChain 继承了 StrFilter 
 * doFilter 执行时,如果 StrFilter 是具体的过滤器,则调用具体的过滤器的 doFilter 方法,
 * 如果 StrFilter 是过滤器链,则调用一系列的过滤器 doFilter 方法
 */
public class StrFilterChain implements StrFilter {

    private List<StrFilter> filterList = new ArrayList<>();

    /**
     * 返回 StrFilterChain 对象可以让使用者重复调用 addFilter 方法
     * 比如 strFilterChain.addFilter(new BlankFilter())
     *                   .addFilter(new EnglishLetterFilter());
     * @param strFilter
     * @return
     */
    public StrFilterChain addFilter(StrFilter strFilter) {
        filterList.add(strFilter);
        return this;
    }

    @Override
    public String doFilter(String str) {
        for (int i = 0; i < filterList.size(); i++) {
            StrFilter strFilter = filterList.get(i);
            str = strFilter.doFilter(str);
        }
        return str;
    }

}

测试:

public class StrTest {
    public static void main(String[] args) {
        String str = "今 天Today是2022年5月26日!";
        StrFilterChain strFilterChain = new StrFilterChain();
        strFilterChain.addFilter(new BlankFilter()).addFilter(new EnglishLetterFilter());
        String result = strFilterChain.doFilter(str);
        System.out.println(result);
    }
}

使用空格和英文字母过滤器后,字符串去掉了对应的字符,如下:

今天是2022年5月26日,26,2022

另一种写法

这种方式的特点是在过滤器中调用另外一个过滤器

入参:

public class RequestStr {
    public String str;
}

过滤器接口 StrFilter2

public interface StrFilter2 {
    void doFilter(StrFilterChain2 strFilterChain, RequestStr requestStr);
}

接口实现类:

public class BlankFilter2 implements StrFilter2 {

    @Override
    public void doFilter(StrFilterChain2 strFilterChain, RequestStr requestStr) {
        System.out.println("BlankFilter begin...");
        requestStr.str = requestStr.str.replaceAll("\\s+", "");
        strFilterChain.doFilter(strFilterChain, requestStr);
        System.out.println("BlankFilter end...");
    }
}
public class EnglishLetterFilter2 implements StrFilter2 {
    @Override
    public void doFilter(StrFilterChain2 strFilterChain, RequestStr requestStr) {
        System.out.println("EnglishLetterFilter begin...");
        requestStr.str = requestStr.str.replaceAll("[A-Za-z]", "");
        strFilterChain.doFilter(strFilterChain, requestStr);
        System.out.println("EnglishLetterFilter end...");
    }
}

过滤器链 StrFilterChain2

index 表示下一个过滤器在 filterList 中的下标

public class StrFilterChain2 implements StrFilter2 {

    private List<StrFilter2> filterList = new ArrayList<>();

    private int index = 0;

    public StrFilterChain2 addFilter(StrFilter2 strFilter) {
        filterList.add(strFilter);
        return this;
    }


    @Override
    public void doFilter(StrFilterChain2 strFilterChain, RequestStr requestStr) {
        if (filterList.size() <= 0) {
            return;
        }
        if (index == filterList.size()) {
            return;
        }
        StrFilter2 strFilter = filterList.get(index);
        index++;
        strFilter.doFilter(strFilterChain, requestStr);
    }
}

测试:

public class StrTest2 {
    public static void main(String[] args) {
        RequestStr requestStr = new RequestStr();
        requestStr.str = "今 天Today是2022年5月26日!";
        StrFilterChain2 strFilterChain = new StrFilterChain2();
        strFilterChain.addFilter(new BlankFilter2()).addFilter(new EnglishLetterFilter2());
        strFilterChain.doFilter(strFilterChain,requestStr);
        System.out.println(requestStr.str);
    }
}

如下:日志打印顺序类似 栈 ,BlankFilter begin 在 EnglishLetterFilter begin. 前打印,而 BlankFilter end. 在 EnglishLetterFilter end 后打印

BlankFilter begin...
EnglishLetterFilter begin...
EnglishLetterFilter end...
BlankFilter end...
今天是2022年5月26日!

使用责任链模式的源码

Tomcat Filter

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

FilterChain

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值