设计模式之责任链模式(ChainOfResponsibility)

设计模式之责任链模式

初始化

场景描述

存入数据库之前,过滤用户输入的文字。


public class Servlet_Main {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问 ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        String r = msg.getMsg();
        r = r.replace("<", "[");
        r = r.replace(">", "]");
        r = r.replace("996", "955");
        msg.setMsg(r);
        System.out.println(r);
    }
}

class Msg {
    String msg;

    public String getMsg() {
        return msg;
    }

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

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

  • 输出结果
大家好:)[script],欢迎访问 ,大家都是955 

经过两步处理, 敏感信息已经过滤掉, 日后如果有过滤非常多的消息, 都写在一块的话, 代码量非常大 , 要修改现有代码 , 可扩展性不好。

过滤器

由于处理字符串的逻辑会变化, 所以封装变化,将变化的代码进行封装处理。

package com.cyc.design.cor.servlet.v1;


public class Servlet_Main {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问 ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        new HtmlFilter().doFilter(msg);
        new SensitiveFilter().doFilter(msg);
        System.out.println(msg);
    }
}

class Msg {
    String msg;

    public String getMsg() {
        return msg;
    }

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

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

//新建一个filter接口, 所有过滤逻辑实现该接口
interface Filter {
    void doFilter(Msg msg);
}

class HtmlFilter implements Filter {
    @Override
    public void doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace("<", "[");
        r = r.replace(">", "]");
        msg.setMsg(r);
    }
}

class SensitiveFilter implements Filter {
    @Override
    public void doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace("996", "955");
        msg.setMsg(r);
    }
}


但是这种依然有问题, 如果有了新的过滤逻辑 , 还是要改动原来的代码

优化过滤器

新建一个Filter的list , 将需要执行的过滤器添加至该list中, 遍历list , 执行过滤逻辑

public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问 ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        List<Filter> filterList = new ArrayList<>();
        filterList.add(new HtmlFilter());
        filterList.add(new SensitiveFilter());
        for (Filter filter : filterList) {
            filter.doFilter(msg);
        }
        System.out.println(msg);
    }

此时的filter向一个链条 , 每个filter执行各自的逻辑 , 如果有新的filter进来,就可以直接添加该filter,这种就叫责任链模式。

在这里插入图片描述

FilterChain

以上只是一个简单的调用链条,距离真正的责任链还有距离。

新建一个FilterChain , 将这些过滤器串成一条链

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

    public void add(Filter f) {
        filterList.add(f);
    }

    //在这个链条上的所有filter都跑一遍
    public void doFilter(Msg msg) {
        for (Filter filter : filterList) {
            filter.doFilter(msg);
        }
    }
}

main方法

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问baidu.com ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        FilterChain fc = new FilterChain();
        fc.add(new HtmlFilter());
        fc.add(new SensitiveFilter());

        fc.doFilter(msg);
        System.out.println(msg);
    }

这里可以优化代码

改造FilterChain

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

    /**
     * 每次调用都返回新的FilterChain
     */
    public FilterChain add(Filter f) {
        filterList.add(f);
        return this;
    }

    //在这个链条上的所有filter都跑一遍
    public void doFilter(Msg msg) {
        for (Filter filter : filterList) {
            filter.doFilter(msg);
        }
    }
}

main方法

public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问baidu.com ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        FilterChain fc = new FilterChain();
        //链式编程
        fc.add(new HtmlFilter()).add(new SensitiveFilter());

        fc.doFilter(msg);
        System.out.println(msg);
    }

当写完这个FilterChain之后 , 如果想要和别的FilterChain连起来应该怎么做?

继续新建Filter

/**
 * 替换笑脸
 */
class FaceFilter implements Filter {
    @Override
    public void doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace(":)", "*_*");
        msg.setMsg(r);
    }
}

/**
 * 补全url
 */
class UrlFilter implements Filter {
    @Override
    public void doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace("baidu.com", "http://www.baidu.com");
        msg.setMsg(r);
    }
}

为了将两个链条连接借来 , FilterChain同样实现Filter接口。

main 方法如下

public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问baidu.com ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        FilterChain fc = new FilterChain();
        //链式编程
        fc.add(new HtmlFilter()).add(new SensitiveFilter());
        
        //新建一个FilterChain fc2, 将他和fc连接起来
        FilterChain fc2 = new FilterChain();
        fc2.add(new FaceFilter()).add(new UrlFilter());
        //这里直接将fc2加入到fc中, 达到链式调用的目的
        fc.add(fc2);
        fc.doFilter(msg);
        System.out.println(msg);
    }

自定义过滤

新需求: 由FilterChain中的某一个Filter决定链条是否继续 , 假如一个有四个Filter, 当执行到了Filter2之后 , 经过处理 , 不再继续执行链条

方案一: 添加if 判断 , 但是这样的话, 每增加一个Filter , 就要加一个if 判断 , 可扩展性较差

方案二: 修改Filter接口, 将doFilter的返回设为booean类型 , 当返回true时, 就继续执行, 当返回为false , 不再执行 , 链条到此结束

完整代码


public class Servlet_Main {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问baidu.com ,大家都是996 ");
        //处理msg, 过滤敏感字,<,> 和996
        FilterChain fc = new FilterChain();
        //链式编程

        fc.add(new HtmlFilter()).add(new SensitiveFilter());

        //新建一个FilterChain fc2, 将他和fc连接起来
        FilterChain fc2 = new FilterChain();
        fc2.add(new FaceFilter()).add(new UrlFilter());
        //这里直接将fc2加入到fc中, 达到链式调用的目的
        fc.add(fc2);
        fc.doFilter(msg);
        System.out.println(msg);
    }
}

class Msg {
    String msg;

    public String getMsg() {
        return msg;
    }

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

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

//新建一个filter接口, 所有过滤逻辑实现该接口
interface Filter {
    boolean doFilter(Msg msg);
}

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

/**
 * 替换敏感字996
 */
class SensitiveFilter implements Filter {
    @Override
    public boolean doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace("996", "955");
        msg.setMsg(r);
        return false;
    }
}

/**
 * 替换笑脸
 */
class FaceFilter implements Filter {
    @Override
    public boolean doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace(":)", "*_*");
        msg.setMsg(r);
        return true;
    }
}

/**
 * 补全url
 */
class UrlFilter implements Filter {
    @Override
    public boolean doFilter(Msg msg) {
        String r = msg.getMsg();
        r = r.replace("baidu.com", "http://www.baidu.com");
        msg.setMsg(r);
        return true;
    }
}

class FilterChain implements Filter{
    List<Filter> filterList = new ArrayList<>();

    /**
     * 每次调用都返回新的FilterChain
     */
    public FilterChain add(Filter f) {
        filterList.add(f);
        return this;
    }

    //在这个链条上的所有filter都跑一遍
    public boolean doFilter(Msg msg) {
        for (Filter filter : filterList) {
            if (!filter.doFilter(msg)) {
                //当某一个Filter返回false后, 就结束该链条, 不再执行
                return false;
            }
        }
        return true;
    }
}


由于在执行SensitiveFilter后, 返回了false , 所以之后的过滤器应该是都不再执行, 查看输出结果如下

Msg{msg='大家好:),[script],欢迎访问baidu.com ,大家都是955 '}

顺序过滤

需求: 参照javax.servlet.Filter和javax.servlet.FilterChain写一个过滤链路

目前有两个过滤器 , SensitiveFilter和HtmlFilter , 要求是request请求进来之后 , 先经过SensitiveFilter, 再经过HtmlFilter , 处理完成后 , 返回response先经过HtmlFilter ,再经过SensitiveFilter

基础代码


public class Servlet_Main {
    public static void main(String[] args) {
        Request request = new Request();
        request.str = "大家好:),<script>,欢迎访问baidu.com ,大家都是996 ";
        //处理msg, 过滤敏感字,<,> 和996
        Response response = new Response();
        response.str = "";

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

class Request {
    String str;
}

class Response {
    String str;
}

//新建一个filter接口, 所有过滤逻辑实现该接口
interface Filter {
    boolean doFilter(Request request,Response response);
}

class HtmlFilter implements Filter {
    @Override
    public boolean doFilter(Request request,Response response) {
        request.str = request.str.replaceAll("<", "[").replaceAll(">", "]");
        return true;
    }
}

/**
 * 替换敏感字996
 */
class SensitiveFilter implements Filter {
    @Override
    public boolean doFilter(Request request,Response response) {
        request.str = request.str.replaceAll("996", "955");
        return true;
    }
}


class FilterChain implements Filter{
    List<Filter> filterList = new ArrayList<>();

    /**
     * 每次调用都返回新的FilterChain
     */
    public FilterChain add(Filter f) {
        filterList.add(f);
        return this;
    }

    //在这个链条上的所有filter都跑一遍
    public boolean doFilter(Request request,Response response) {
        for(Filter f : filterList ){
            f.doFilter(request, response);
        }
        return true;
    }
}


用最直观的方式处理response
直接将response的处理放在request的下面


public class Servlet_Main {
    public static void main(String[] args) {
        Request request = new Request();
        request.str = "大家好:),<script>,欢迎访问baidu.com ,大家都是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 {
    boolean doFilter(Request request, Response response);
}

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

class Request {
    String str;
}

class Response {
    String str;
}

class SensitiveFilter implements Filter {
    @Override
    public boolean doFilter(Request request, Response response) {
        request.str = request.str.replaceAll("996", "955");
        response.str += "--SensitiveFilter()";
        return true;
    }
}


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

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

    public boolean doFilter(Request request, Response response) {

        for(Filter f : filters ){
            f.doFilter(request, response);
        }
        return true;
    }
}

查看结果

大家好:)[script],欢迎访问baidu.com ,大家都是955 
response--HTMLFilter()--SensitiveFilter()

可以看到request请求 , 是按照顺序处理了, 但是response却没有 , response返回应该先经过sensitiveFilter过滤器, 然后再经过HTMLFilter过滤器, 输出结果应为response–SensitiveFilter()–HTMLFilter() 才对

继续优化

在filterChain中处理加入位置的记录
同时在filter中加入第三个参数

package com.cyc.design.cor.servlet.v3;

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

public class Servlet_Main {
    public static void main(String[] args) {
        Request request = new Request();
        request.str = "大家好:),<script>,欢迎访问baidu.com ,大家都是996 ";
        Response response = new Response();
        response.str = "response";

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

    }
}

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

class HTMLFilter implements Filter {
    @Override
    public boolean doFilter(Request request, Response response, FilterChain chain) {
        request.str = request.str.replaceAll("<", "[").replaceAll(">", "]") + "HTMLFilter()";
        //这里如果调用chain.doFilter, 程序就会继续执行过滤, 否则, 执行到这里就会结束
        chain.doFilter(request, response, chain);
        //先走完request的请求后 , 才开始执行response的过滤逻辑
        response.str += "--HTMLFilter()";
        return true;
    }
}

class Request {
    String str;
}

class Response {
    String str;
}

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


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

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

    public boolean doFilter(Request request, Response response, FilterChain chain) {
        if (index == filters.size()) return false;
        Filter f = filters.get(index);
        index++;

        return f.doFilter(request, response, chain);
    }
}

这里采用递归的方式

模拟Servlet.Filter

完全模拟Serverlet中的FilterChain

servelet.filter, spring mvc, structs 2 采用的就是这种方式

package com.cyc.design.cor.servlet.v4;

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

public class Servlet_Main {
    public static void main(String[] args) {
        Request request = new Request();
        request.str = "大家好:),<script>,欢迎访问baidu.com ,大家都是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 f = filters.get(index);
        index++;
        //将this(当前对象)传进去, 继续过滤
        f.doFilter(request, response, this);
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

意田天

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值