前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式——责任链

设计模式——责任链

作者头像
mathor
发布2018-09-19 15:22:31
5360
发布2018-09-19 15:22:31
举报
文章被收录于专栏:mathor
问题引入

 假设有一个论坛,很多人可以在上面发消息,但是这些消息,有的需要过滤敏感字眼,有的又需要修改关键字,举个简单的例子

代码语言:javascript
复制
String msg = "你好,中国澳门皇家赌场,<html>性感xx在线...</html>,:)";

 就上面这消息,我们就有两处要进行屏蔽,首先是敏感字:“中国澳门皇家赌场,性感”,其次是html代码“<html>,</html>”要修改成“[html],[/html]”,不然消息发出来可能会对结果产生影响。  针对上面的问题,我们通常都是这么做的

代码语言:javascript
复制
public class Main() {
    public static void main(String[] args) {
        String msg = "你好,中国澳门皇家赌场,<html>性感xx在线...</html>,:)";
        msg = msg.replace("中国澳门皇家赌场","").replace("性感","").replace("<","[").replace(">","]");
        System.out.println(msg);
    }
}

责任链

 上面只是非常简单的一种写法,但是接下来我们要站在面向对象的角度去思考这个程序应该怎么写。马士兵老师说:“设计模式最基本的要求就是先写测试

代码语言:javascript
复制
public class Main() {
    public static void main(String[] args) {
        String msg = "你好,中国澳门皇家赌场,<html>性感xx在线...</html>,:)";
        msg = msg.replace("中国澳门皇家赌场","").replace("性感","").replace("<","[").replace(">","]");
        System.out.println(msg);
    }
}

 信息过滤有两种,一种是html代码过滤,一种是敏感字过滤,所以我们干脆创建一个接口Filter,然后创建一个HtmlFilter类实现接口的doFilter方法,另一个SesitiveFilter类也实现doFilter方法

代码语言:javascript
复制
//Filter接口
public interface Filter {
    String doFilter(String str);
}

代码语言:javascript
复制
//HtmlFilter类
public class HtmlFilter implements Filter {
    
    @Override
    public String doFilter(String str) {
        String r = str.replace("<", "[").replace(">","]");
        return r;
    }
}

代码语言:javascript
复制
//SesitiveFilter类
public class SesitiveFilter implements Filter {

    @Override
    public String doFilter(String str) {
        String r = str.replace("中国澳门皇家赌场","").replace("性感","");
        return r;
    }
}

代码语言:javascript
复制
//MsgProcessor类
public class MsgProcessor {
    private String msg;
    Filter[] filters = {new HtmlFilter(),new SesitiveFilter()};
    public void set(String msg) {
        this.msg = msg;
    }
    public String get() {
        return msg;
    }
    public String process() {
        String r = msg;
        for(Filter f : filters)
            r = f.doFilter(r);
        return r;
    }
}

 整个代码文件结构如下图所示:

 这样写,有两个好处,假设我需要新增一个过滤规则,只需要新建一个类,实现接口的方法,然后将这个类增加到Filter数组中即可。还有一个好处,就是可以使过滤规则有一定的顺序,比方说一个新生来上学,他需要先交钱,再领书,再领被子,再进教室......Filter数组里匿名对象的顺序,就是执行的顺序。  可以用一幅图来表示责任链这种设计模式的过程:

 黑色的箭头可以理解为一个消息的输入,经过三个黄色过滤器后,最终输出到数据库或者其他地方。

引入新的责任链

 再考虑一个问题,假如又有一系列的责任链,需要将新的责任链插在原责任链的中间执行(具体见下图),应该怎么做?

 用一个新的类FilterChain,里面有一个ArrayList,专门存放各种实现Filter的类

代码语言:javascript
复制
//FilterChain类
import java.util.*;
public class FilterChain {
    List<Filter> filters = new ArrayList<Filter>();
    public FilterChain add(Filter f) {
        this.filters.add(f);
        return this;
    }
    public String doFilter(String str) {
        String r = str;
        for(Filter f:filters) 
            r = f.doFilter(r);
        return r;
    }
}

 MsgProcessor类也要修改

代码语言:javascript
复制
//MsgProcessor类
public class MsgProcessor {
    private String msg;
    //Filter[] filters = {new HtmlFilter(),new SesitiveFilter()};
    FilterChain fc;
    public FilterChain getFc() {
        return fc;
    }
    public void setFc(FilterChain fc) {
        this.fc = fc;
    }
    public void set(String msg) {
        this.msg = msg;
    }
    public String get() {
        return msg;
    }
    public String process() {
        return fc.doFilter(msg);
    }
}

 最后是Main

代码语言:javascript
复制
//Main类
public class Main {
    public static void main(String[] args) {
        String msg = "你好,中国澳门皇家赌场,<html>性感xx在线...</html>,:)";
        MsgProcessor mp = new MsgProcessor();
        mp.set(msg);
        FilterChain fc = new FilterChain();
        fc.add(new HtmlFilter()).add(new SesitiveFilter());
        mp.setFc(fc);
        String result = mp.process();
        System.out.println(result);
    }
}

 整个执行过程再讲述一遍,首先Main方法把msg传给MsgProcess,然后创建一个FilterChain对象,调用其add方法,往里面添加很多种Filter,然后将FilterChain对象也传给MsgProcess,最后调用MsgProcess中的process方法。process方法会执行fc.doFilter(msg),doFilter函数是将fc中的所有Filter执行一遍。具体执行流程可以看下图:

服务器客户端责任链

 新的问题,客户端Client发送一个消息,经过Filter1,Filter2,然后传给服务器端Server。接下来服务器端要给一个消息反馈给客户端,因此要依次经过Filter2,Filter1(很明显,过去和回来经过Filter的顺序肯定是相反的)  这有点栈的思想在里面,将Client端发送出去时遇到的各种Filter压栈,然后在Server端传输回来的时候依次弹栈,类似的思想。  首先客户端和服务器端的类肯定要有

代码语言:javascript
复制
//Server端
public class ServerFilter {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

代码语言:javascript
复制
//Client端
public class ClientFilter {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

代码语言:javascript
复制
//Filter接口
public interface Filter {
    void doFilter(ClientFilter client,ServerFilter server,FilterChain chain);
}

代码语言:javascript
复制
//HtmlFilter类
public class HtmlFilter implements Filter {
    
    @Override
    public void doFilter(ClientFilter client,ServerFilter server,FilterChain chain) {
        client.setStr(client.getStr().replace("<", "[").replace(">","]") + "---HtmlFilter()");
        chain.doFilter(client, server, chain);
        server.setStr(server.getStr() + "---HtmlFilter()");
    }
}

代码语言:javascript
复制
//SesitiveFilter类
public class SesitiveFilter implements Filter {

    @Override
    public void doFilter(ClientFilter client,ServerFilter server,FilterChain chain) {
        client.setStr(client.getStr().replace("中国澳门皇家赌场","").replace("性感","") + "---SesitiveFilter()");
        chain.doFilter(client, server, chain);
        server.setStr(server.getStr() + "---SesitiveFilter()");
    }
}

代码语言:javascript
复制
//FilterChain类
import java.util.*;
public class FilterChain implements Filter{
    int idx = 0;
    List<Filter> filters = new ArrayList<Filter>();
    public FilterChain add(Filter f) {
        this.filters.add(f);
        return this;
    }
    @Override
    public void doFilter(ClientFilter client, ServerFilter server, FilterChain chain) {
        if(idx == filters.size())
            return;
        Filter f = filters.get(idx);
        idx++;
        f.doFilter(client, server, chain);
    }
}

代码语言:javascript
复制
MsgProcessor类
public class MsgProcessor {
    private String msg;
    //Filter[] filters = {new HtmlFilter(),new SesitiveFilter()};
    FilterChain fc;
    public FilterChain getFc() {
        return fc;
    }
    public void setFc(FilterChain fc) {
        this.fc = fc;
    }
    public void set(String msg) {
        this.msg = msg;
    }
    public String get() {
        return msg;
    }
    public void process(ClientFilter client,ServerFilter server) {
        fc.doFilter(client, server, fc);
    }
}

代码语言:javascript
复制
//Main类
public class Main {
    public static void main(String[] args) {
        String msg = "你好,中国澳门皇家赌场,<html>性感xx在线...</html>,:)";
        MsgProcessor mp = new MsgProcessor();
        FilterChain fc = new FilterChain();
        fc.add(new HtmlFilter()).add(new SesitiveFilter());
        mp.setFc(fc);
        ClientFilter client = new ClientFilter();
        client.setStr(msg);;
        ServerFilter server = new ServerFilter();
        server.setStr("Server");;
        mp.process(client, server);
        System.out.println(client.getStr());
        System.out.println(server.getStr());
    }
}

结语

 马士兵老师说:“不要问学什么有用学什么没用,直接去招聘网站看看,现在招什么人才,需要会什么技术”

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题引入
  • 责任链
  • 引入新的责任链
  • 服务器客户端责任链
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档