06 ChainOfResponsibility责任链模式

场景1

一个网站,可以留言评论发消息等。消息通过前端输入文字,然后传给后端,再进入数据库,然后在网站展示出来。如果文字中包含网页脚本,会破坏我们的网页;如果包含敏感词,会对网站造成更严重的影响,甚至可能触犯法律法规,所以我们需要对消息进行过滤,对过滤处理的有问题的文字进行替换处理。

我们定义一个消息类:

package org.garen.cor;

/**
 * 消息
 */
public class Msg {
    private String name;
    private 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 "Msg{" +
                "name='" + name + '\'' +
                ", msg='" + msg + '\'' +
                '}';
    }
}

最简单的处理

测试类:

package org.garen.cor;

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");

        // 处理网页脚本
        String r = msg.getMsg();
        r = r.replace("<", "[");
        r = r.replace(">", "]");
        msg.setMsg(r);
        System.out.println(r);

        // 处理敏感词
        r = r.replace("996", "955");
        msg.setMsg(r);
        System.out.println(r);
    }

}

运行结果:

大家好:),[script],欢迎访问www.garen.org,大家都是996
大家好:),[script],欢迎访问www.garen.org,大家都是955

这种方式简单,但是不利于扩展。如果有新的条件需要处理的,就要修改代码。
使用设计模式,是把简单的程序复杂化,哪里会发生变化,就封装哪里。程序复杂了,但是提高了扩展性。

封装变化

消息过滤接口:

package org.garen.cor;

/**
 * 消息过滤接口
 */
public interface MsgFilter {
    void doFilter(Msg m);
}

网页脚本过滤器:

package org.garen.cor;

/**
 * 网页脚本过滤器
 */
public class HTMLFilter implements MsgFilter{
    @Override
    public void doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("<", "[");
        s = s.replace(">", "]");
        m.setMsg(s);
    }
}

敏感词过滤器:

package org.garen.cor;

/**
 * 敏感词过滤器
 */
public class SensitiveFilter implements MsgFilter{
    @Override
    public void doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("996", "955");
        m.setMsg(s);
    }
}

测试类:

package org.garen.cor;

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");

        // 处理网页脚本
        MsgFilter htmlFilter = new HTMLFilter();
        htmlFilter.doFilter(msg);
        // 处理敏感词
        MsgFilter sensitiveFilter = new SensitiveFilter();
        sensitiveFilter.doFilter(msg);
        // 打印消息
		System.out.println(msg);
    }

}

运行结果:

Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}

这样,如果有新的条件需要处理的,只需要增加一个新的过滤器,修改一下测试类即可。

把过滤器加入集合

测试类:

package org.garen.cor;

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

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");

        // 过滤器集合
        List<MsgFilter> filters = new ArrayList<>();
        filters.add(new HTMLFilter());
        filters.add(new SensitiveFilter());
        // add new filter ...

        // 遍历集合,进行过滤
        for (MsgFilter filter : filters) {
            filter.doFilter(msg);
        }
    }

}

运行结果:

Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}

我们把过滤器加入到集合中,然后遍历集合进行过滤。
如果有新的条件需要处理的,只需要增加一个新的过滤器,加入过滤器集合中即可。
遍历过滤器集合,依次处理,像不像一个链呢?

过滤器链条类

我们继续改造代码,创建一个过滤器链条类,并提供新增、删除、过滤等方法。
过滤器链条类:

package org.garen.cor;

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

public class MsgFilterChain {
    List<MsgFilter> filters = new ArrayList<>();

    public void add(MsgFilter filter) {
        filters.add(filter);
    }

    // delete省略

    public void doFilter(Msg msg) {
        for (MsgFilter filter : filters) {
            filter.doFilter(msg);
        }
    }

}

测试类:

package org.garen.cor;

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");
        
        MsgFilterChain fc = new MsgFilterChain();
        fc.add(new HTMLFilter());
        fc.add(new SensitiveFilter());

        fc.doFilter(msg);

        System.out.println(msg);
    }

}

运行结果:

Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}

这样有什么好处吗?看起来就是把测试类中的过滤器集合和遍历的代码移到一个MsgFilterChain类中。

改造add方法

我们改造一下add方法,就有所不同了。
过滤器链条类的add方法:

public MsgFilterChain add(MsgFilter filter) {
        filters.add(filter);
        return this;
    }

测试类的添加过滤器代码:

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

在有新的过滤器加入,就.add一直加下去,形成一条链。

再多加一个链条

笑脸过滤器:

package org.garen.cor;

public class FaceFilter implements MsgFilter{
    @Override
    public void doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace(":)", "^v^");
        m.setMsg(s);
    }
}

url过滤器:

package org.garen.cor;

public class UrlFilter implements MsgFilter{
    @Override
    public void doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("www.garen.org", "http://www.garen.org");
        m.setMsg(s);
    }
}

测试类:

package org.garen.cor;

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");

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

        // 新增加的链条2
        MsgFilterChain fc2 = new MsgFilterChain();
        fc2.add(new FaceFilter()).add(new UrlFilter());

        fc.doFilter(msg);
        fc2.doFilter(msg);  // 链条2的处理

        System.out.println(msg);
    }

}

运行结果:

Msg{name=‘null’, msg=‘大家好v,[script],欢迎访问http://www.garen.org,大家都是955’}

两个链条连起来

修改MsgFilterChain也实现MsgFilter接口,fc.add(fc2)把两个链条连起来

过滤器链条类:

package org.garen.cor;

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

public class MsgFilterChain implements MsgFilter{
    List<MsgFilter> filters = new ArrayList<>();

    public MsgFilterChain add(MsgFilter filter) {
        filters.add(filter);
        return this;
    }

    // delete省略

    @Override
    public void doFilter(Msg msg) {
        for (MsgFilter filter : filters) {
            filter.doFilter(msg);
        }
    }

}

测试类:

package org.garen.cor;

public class Main {

    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问www.garen.org,大家都是996");

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

        // 新增加的链条2
        MsgFilterChain fc2 = new MsgFilterChain();
        fc2.add(new FaceFilter()).add(new UrlFilter());

        // 链条连起来
        fc.add(fc2);

        // 两个链条一起处理
        fc.doFilter(msg);

        System.out.println(msg);
    }

}

运行结果:

Msg{name=‘null’, msg=‘大家好v,[script],欢迎访问http://www.garen.org,大家都是955’}

场景2

如果我想控制,执行一个过滤器后,是否继续执行,要怎么做?
修改MsgFilter,返回值改成布尔类型

package org.garen.cor;

/**
 * 消息过滤接口
 */
public interface MsgFilter {
    boolean doFilter(Msg m);
}

修改所有过滤器实现类,每个过滤器自己的逻辑判断返回ture/false。这里我们就不写逻辑判断了,敏感词过滤器返回false,其它返回true。

网页过滤器:

package org.garen.cor;

/**
 * 网页脚本过滤器
 */
public class HTMLFilter implements MsgFilter{
    @Override
    public boolean doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("<", "[");
        s = s.replace(">", "]");
        m.setMsg(s);
        return true;
    }
}

敏感词过滤器:

package org.garen.cor;

/**
 * 敏感词过滤器
 */
public class SensitiveFilter implements MsgFilter{
    @Override
    public boolean doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("996", "955");
        m.setMsg(s);
        return false;
    }
}

笑脸过滤器:

package org.garen.cor;

public class FaceFilter implements MsgFilter{
    @Override
    public boolean doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace(":)", "^v^");
        m.setMsg(s);
        return true;
    }
}

url过滤器:

package org.garen.cor;

public class UrlFilter implements MsgFilter{
    @Override
    public boolean doFilter(Msg m) {
        String s = m.getMsg();
        s = s.replace("www.garen.org", "http://www.garen.org");
        m.setMsg(s);
        return true;
    }
}

链条类,也实现了接口,doFilter也要改成返回布尔类型。同时,如果过滤器返回false,则不再继续执行。
链条类:

package org.garen.cor;

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

public class MsgFilterChain implements MsgFilter{
    List<MsgFilter> filters = new ArrayList<>();

    public MsgFilterChain add(MsgFilter filter) {
        filters.add(filter);
        return this;
    }

    // delete省略

    @Override
    public boolean doFilter(Msg msg) {
        for (MsgFilter filter : filters) {
            if(!filter.doFilter(msg)) return false;
        }
        return true;
    }

}

测试类不变,测试结果:

Msg{name=‘null’, msg=‘大家好:),[script],欢迎访问www.garen.org,大家都是955’}

执行完敏感词过滤器后就结束了。

模拟Servlet的Filter

要求:
request执行顺序:filter1,filter2
response执行顺序:filter2,filter1

请求响应对象:

package org.garen.cor2;

public class Request {
    String str;
}
package org.garen.cor2;

public class Response {
    String str;
}

过滤器接口:

package org.garen.cor2;

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

过滤器:

package org.garen.cor2;

public class HTMLFilter implements Filter{

    @Override
    public void doFilter(Request request, Response response, FilterChain filterChain) {
        System.out.println("HTMLFilter request: " + request.str);
        filterChain.chain(request, response);
        System.out.println("HTMLFilter response: " + response.str);
    }
}
package org.garen.cor2;

public class UrlFilter implements Filter{
    @Override
    public void doFilter(Request request, Response response, FilterChain filterChain) {
        System.out.println("UrlFilter request: " + request.str);
        filterChain.chain(request, response);
        System.out.println("UrlFilter response: " + response.str);
    }
}

链条:

package org.garen.cor2;

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

public class FilterChain{

    List<Filter> filters = new ArrayList<>();

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

    int i = 0;
    public void chain(Request request, Response response) {
        if (i == filters.size()) return ;
        Filter filter = filters.get(i);
        i++;
        filter.doFilter(request, response, this);
    }
}

测试类:

package org.garen.cor2;

public class Main {
    public static void main(String[] args) {
        // 请求响应对象
        Request request = new Request();
        request.str = "REQUEST";
        Response response = new Response();
        response.str = "RESPONSE";
        // 加入链条
        FilterChain filterChain = new FilterChain();
        filterChain.add(new HTMLFilter());
        filterChain.add(new UrlFilter());
        // 执行
        filterChain.chain(request, response);
    }

}

运行结果:

HTMLFilter request: REQUEST
UrlFilter request: REQUEST
UrlFilter response: RESPONSE
HTMLFilter response: RESPONSE

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值