【学习笔记】设计模式-责任链模式(Chain Of Responsibility)

0 设计模式

不了解设计模式的小伙伴可以通过这篇文章了解一下什么是设计模式

https://blog.csdn.net/qq_42874315/article/details/120006447?spm=1001.2014.3001.5502

1 责任链模式

责任链模式是我个人认为比较重要的一种设计模式,在我日常的编码中也较常用到,责任链模式的本质就是过滤器,责任链模式可以使过滤条件自由组合,降低了代码的耦合度,并且扩展性非常高,面向责任链过滤,而不面向具体的过滤器去过滤。

原理图

在这里插入图片描述

2 实现思路

在这里插入图片描述

3 需要的类

  1. 过滤器接口

  2. 多个实现过滤器接口的具体过滤器

  3. 实现过滤器接口的具体责任链(在责任链的doFilter中可以提前就对过滤器进行注册)

    责任链中需要一个额外的方法add,用来添加具体的过滤器

    需要一个含有多个Filter集合(注册过滤器用的)

  4. 消息实体(往过滤器中传入的)

  5. 额外的一个测试方法(需要注意的是,提前将过滤器添加到责任链中,面向责任链过滤,而不面向具体的过滤器去过滤)

4 具体实现

4.1 Filter(创建过滤器接口)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:44
 */
public interface Filter {
    boolean doFilter(Message m);
}

4.2 多个实现过滤器接口的具体过滤器

4.2.1 FaceFilter(将:) 替换为 V)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:45
 */
public class FaceFilter implements Filter {
    @Override
    public boolean doFilter(Message m) {
        // 处理msg
        String r = m.getMsg();
        r = r.replace(":)","^V^");
        m.setMsg(r);
        return true;
    }
}

4.2.2 HtmlFilter(将< 替换为 [ 将> 替换为 ])

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:45
 */
public class HtmlFilter implements Filter {
    @Override
    public boolean doFilter(Message m) {
        // 处理msg
        String r = m.getMsg();
        r = r.replace('<','[');
        r = r.replace('>',']');
        m.setMsg(r);
        return true;
    }
}

4.2.3 SensitiveFilter(将996 替换为 007)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:54
 */
public class SensitiveFilter implements Filter {
    @Override
    public boolean doFilter(Message m) {
        // 处理msg
        String r = m.getMsg();
        r = r.replace("996","007");
        m.setMsg(r);
        return true;
    }
}

4.3 FilterChain(实现过滤器接口的具体责任链)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:47
 */
public class FilterChain implements Filter {
    List<Filter> filters = new ArrayList<>();

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

    @Override
    public boolean doFilter(Message m) {
        for (Filter filter : filters) {
            if (!filter.doFilter(m)){
                return false;
            }
        }
        return true;
    }
}

4.4 Message(消息实体,根据实际情况完全可以用一个字符串去替代)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:44
 */
public class Message {
    String name;
    String msg;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "Message{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

4.5 测试类

注:在责任链的doFilter中可以提前就对过滤器进行注册,这样在测试类中就不用再注册过滤器了(具体示例见扩展)

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/1 13:50
 */
public class Main {
    public static void main(String[] args) {
        Message message = new Message();
        message.setMsg("大家好:),<script>,我是程序员五条,大家都是996");
        // 过滤表情和HTML的链条
        FilterChain filterChain = new FilterChain();
        filterChain.add(new FaceFilter()).add(new HtmlFilter());

        // 过滤996的链条
        FilterChain filterChain1 = new FilterChain();
        filterChain1.add(new SensitiveFilter());

        // 两个链条合并(也可以单用)
        filterChain.add(filterChain1);

        // 执行链条
        filterChain.doFilter(message);
        System.out.println(message);
    }
}

5 扩展(链式拦截)

5.1 思路

  1. 定义多条拦截规则
  2. 只要其中一条不符合,这条消息就可以视为非法消息

5.2 实例:校验SQL

5.2.1 SqlInterceptor(拦截器接口)

5.2.2 拦截接口的实现类

IllegalKeywordsInterceptor(SQL非法关键字校验,只允许查询select)

/**
 * SQL非法关键字校验
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/17 15:08
 */
@Component
public class IllegalKeywordsInterceptor implements SqlInterceptor{

    static List<String> illegalKeywordsList = new ArrayList<>();

    static {
        illegalKeywordsList.add("update ");
        illegalKeywordsList.add("drop ");
        illegalKeywordsList.add("alter ");
        illegalKeywordsList.add("delete ");
        illegalKeywordsList.add("insert ");
        illegalKeywordsList.add("create ");
        illegalKeywordsList.add("grant ");
        illegalKeywordsList.add("perpare ");
        illegalKeywordsList.add("execute ");
        illegalKeywordsList.add("deallocate ");
        illegalKeywordsList.add("truncate ");
    }

    @Override
    public void doInterceptor(String sql) {
        // SQL全部转小写
        String lowerSql = sql.toLowerCase();
        for (String illegalKeywords : illegalKeywordsList) {
            if (lowerSql.contains(illegalKeywords)){
                throw new SqlCheckException("SQL中包含非法关键字:" + illegalKeywords);
            }
        }
    }
}

SqlLengthInterceptor(SQL长度校验)

/**
 * SQL长度校验
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/20 11:20
 */
public class SqlLengthInterceptor implements SqlInterceptor{
    @Override
    public void doInterceptor(String sql) throws SqlCheckException {
        if (sql.length() < 20) {
            throw new SqlCheckException("SQL长度至少需要大于等于20");
        }
    }
}

5.2.3 SqlCheckInterceptorChain(拦截链)

/**
 * SQL校验链
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/17 15:09
 */
public class SqlCheckInterceptorChain implements SqlInterceptor{

    List<SqlInterceptor> interceptors = new ArrayList<>();

    private SqlCheckInterceptorChain add(SqlInterceptor sqlInterceptor){
        interceptors.add(sqlInterceptor);
        return this;
    }

    @Override
    public void doInterceptor(String sql) {
        add(new IllegalKeywordsInterceptor());
        add(new SqlLengthInterceptor());
        for (SqlInterceptor interceptor : interceptors) {
            interceptor.doInterceptor(sql);
        }
    }
}

5.2.4 测试类

这里我已经提前将多个拦截规则提前注册到拦截链中了(见拦截链代码的doInterceptor()),所以在调用的时候只传入消息即可

/**
 * @Author ChenJiahao(程序员五条)
 * @Date 2021/8/17 15:15
 */
public class Main {
    public static void main(String[] args) {
        new SqlCheckInterceptorChain().doInterceptor("update public.user set username = '程序员五条' where id = 1");
    }
}

6 思维导图

在这里插入图片描述

7 示例源码地址

https://github.com/ChenJiahao0205/design-pattern/tree/master

最后

我是通过马士兵老师的视频和菜鸟教程学习的,部分内容可能会有雷同

想阅读更多设计模式相关文章,欢迎到我的专栏【设计模式学习笔记】、【设计模式】中去查看

在23篇设计模式文章发布完成之后,我会公开完整的思维导图,点关注,不迷路

感谢大家看到这里,文章如有不足,欢迎大家指出;彦祖点个赞吧彦祖点个赞吧彦祖点个赞吧,欢迎关注程序员五条

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五条Programmer

比心~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值