设计模式之责任链模式(Chain of Responsibility)

简单概念

当一个请求需要经过多级过滤处理时,这个多级处理的每一个流程串起来就是一个责任链,每一个流程负责自己的责任。这个请求可能经过了多个流程的处理,也可能只经过了一个流程的处理,甚至没有流程处理。

例子:

某媒体需要对用户发布的文章做一些处理,需要去除敏感词,去除HTML代码,补全链接等。(就像打游戏,在队友特别坑的情况下,我们都用拼音来骂队友:‘laji’,防止系统处理成‘**’)

还有典型的javaEE java.javax.servlet Filter过滤器,这个最后再说。

 

上代码:

介绍一下待出场的类,Msg,文章类,发布待处理的文章;

package com.zl.chainOfResponsibility;

public class Msg {
    private String msg;

    public String getMsg() {
        return msg;
    }

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

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

 

Filter,文章处理抽象接口;

package com.zl.chainOfResponsibility;

public interface Filter {
    public void doFilter(Msg msg);
}

 

SensitiveWordFilter,Filter实现类,敏感词的过滤处理(具体情况具体处理,为了简便,我就只处理了“草”字)

package com.zl.chainOfResponsibility;

public class SensitiveWordFilter implements Filter{
    @Override
    public void doFilter(Msg msg) {
        String s = msg.getMsg();
        s = s.replaceAll("草", "*");
        msg.setMsg(s);
    }
}

HTMLFilter,Filter实现类,html代码过滤处理,例如文章有“<p>xxx</p>”字段,为保护文章样式,需要替换掉<p></p>(这里也是简便处理)

package com.zl.chainOfResponsibility;

public class HTMLFilter implements Filter{
    @Override
    public void doFilter(Msg msg) {
        String s =msg.getMsg();
        s = s.replace("<p>","");
        s = s.replace("</p>","");
        msg.setMsg(s);
    }
}

LinkFilter,Filter实现类,链接补全过滤处理

package com.zl.chainOfResponsibility;

public class LinkFilter implements Filter{
    @Override
    public void doFilter(Msg msg) {
        String s = msg.getMsg();
        s = s.replace("xxxxxx.com", "http://www.xxxxxx.com");
        msg.setMsg(s);
    }
}

接着main方法测试

package com.zl.chainOfResponsibility;

public class Main {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
        new HTMLFilter().doFilter(msg);
        new SensitiveWordFilter().doFilter(msg);
        new LinkFilter().doFilter(msg);
        System.out.println(msg);
    }
}

 

 

这就是责任链吗?

显然还不够完善,当我们需要添加扩展新的过滤处理时,主体程序main方法中需要添加修改代码,这并不符合对内修改关闭,对外扩展开放的原则。

 

升级:

抽象出“处理链条”,我先内置了3个默认过滤处理

package com.zl.chainOfResponsibility;

import java.util.LinkedList;
import java.util.List;

public class FilterChain implements Filter{
    static List<Filter> filters = new LinkedList<>();
    static {
        filters.add(new SensitiveWordFilter());
        filters.add(new HTMLFilter());
        filters.add(new LinkFilter());
    }
    public void doFilter(Msg msg){
        for (int i = 0; i < filters.size(); i++) {
            filters.get(i).doFilter(msg);
        }
    }
    public void add(Filter filter){
        filters.add(filter);
    }
    public void remove(Filter filter){
        filters.remove(filter);
    }
}

 此时的主体Main类

package com.zl.chainOfResponsibility;

public class Main {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
        FilterChain chain = new FilterChain();
        chain.doFilter(msg);
        System.out.println(msg);
    }
}

至此大功告成,当我们再需要扩展新的过滤处理,或者需要移除默认配置时,只需要通过配置类,或者配置文件去修改即可。主体类再也不用变了。

 

为什么FilterChain也实现了Filter接口?

每一个单独的Filter实现是整个FilterChain的一部分,那部分的FliterChain不也是整体FilterChain的一部分嘛,这样的话链条和链条之间也是可以连接的移除的。

 

怎么样中断链条的执行?

把doFilter方法改成带返回值的,如boolean,如果当前条件满足终止条件返回相应值即可。

最后来谈谈javaEE中 java.javax.servlet Filter

 先把Api粘过来

Filter接口:

 

 

 FilterChain接口:

 

 

 

 那么Java官方是怎么设计责任链的呢?

 

 

 如上图,假如我们定义了三个Filter的实现

当一个客户端请求进来后,它依次经过filter1,filter2,filter3的处理;

并且当服务器响应数据返回时也通过这些filter进行后续的处理,它依次经过filter3,filter2,filter1

 

我们还通过上面的例子进行一下模拟

将上述Msg类更名Request类(方便理解)

package com.zl.chainOfResponsibility.servlet;

public class Request {
    private String msg;

    public String getMsg() {
        return msg;
    }

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

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

添加Response类

package com.zl.chainOfResponsibility.servlet;

public class Response {
    String msg;

    public String getMsg() {
        return msg;
    }

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

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

Filter接口

(让每一个filter的实现者都持有整个链条的引用)

package com.zl.chainOfResponsibility.servlet;

public interface Filter {
    public void doFilter(Request req, Response resp, FilterChain chain);
}

SensitiveWordFilter实现

(在每一个filter实现中,当它处理完了request请求,紧接着就通过持有链条的引用去调用下一个filter实现,直到所有的filters都执行完毕)

package com.zl.chainOfResponsibility.servlet;

public class SensitiveWordFilter implements Filter {
    @Override
    public void doFilter(Request req, Response resp, FilterChain chain) {
        String s = req.getMsg();
        s = s.replaceAll("草", "*");
        req.setMsg(s);
        chain.doFilter(req, resp, chain);
        String s2 = resp.getMsg();
        s2 = s2.concat("SensitiveWordFilter__");
        resp.setMsg(s2);
    }
}

HTMLFilter实现

package com.zl.chainOfResponsibility.servlet;

public class HTMLFilter implements Filter {
    @Override
    public void doFilter(Request req, Response resp, FilterChain chain) {
        String s =req.getMsg();
        s = s.replace("<p>","");
        s = s.replace("</p>","");
        req.setMsg(s);
        chain.doFilter(req, resp, chain);
        String s2 = resp.getMsg();
        s2 = s2.concat("HTMLFilter__");
        resp.setMsg(s2);
    }
}

LinkFilter实现

package com.zl.chainOfResponsibility.servlet;

public class LinkFilter implements Filter {
    @Override
    public void doFilter(Request req, Response resp, FilterChain chain) {
        String s = req.getMsg();
        s = s.replace("xxxxxx.com", "http://www.xxxxxx.com");
        req.setMsg(s);
        chain.doFilter(req, resp, chain);
        String s2 = resp.getMsg();
        s2 = s2.concat("LinkFilter__");
        resp.setMsg(s2);
    }
}

把Filter串起来的链条类FilterChain

(在FilterChain中判断当所有的filters都执行完毕时,开始回溯,依次再反向调用filters处理服务器的响应数据)

package com.zl.chainOfResponsibility.servlet;

import java.util.LinkedList;
import java.util.List;

public class FilterChain implements Filter {
    int index = 0;
    static List<Filter> filters = new LinkedList<>();
    static {
        filters.add(new SensitiveWordFilter());
        filters.add(new HTMLFilter());
        filters.add(new LinkFilter());
    }
    public void doFilter(Request req, Response resp, FilterChain chain){
        if (filters.size() == index){
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(req, resp, chain);
    }
    public void add(Filter filter){
        filters.add(filter);
    }
    public void remove(Filter filter){
        filters.remove(filter);
    }
}

最后Main主体类

package com.zl.chainOfResponsibility.servlet;

public class Main {
    public static void main(String[] args) {
        Request req = new Request();
        req.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
        Response resp = new Response();
        resp.setMsg("");
        FilterChain chain = new FilterChain();
        chain.doFilter(req, resp, chain);
        System.out.println(req);
        System.out.println(resp);
    }
}

测试结果:(我们在FilterChain中通过静态块默认初始化链条顺序为SensitiveWordFilter,HTMLFilter,LinkFilter

 

 

 

 

posted @ 2020-09-15 15:24  风子磊  阅读(232)  评论(0编辑  收藏  举报