JAVA设计模式之(十七)责任链模式

本文继续介绍23种设计模式系列之责任链模式。

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。Tomcat中的Filter就是使用了责任链模式,创建一个Filter除了要在web.xml文件中做相应配置外,还需要实现javax.servlet.Filter接口。

为了方便理解,责任链模式直接用马士兵老师中的一个例子来讲解,做下笔记也方便自己以后的复习查询:

我们有一个字符串String msg = “:):,<script>,敏感,被就业,网络授课”;我们希望应用以下三个规则对字符串进行过滤和谐处理:

  • 将字符串中出现的"<>“符号替换成”[]"
  • 处理字符串中的敏感信息,将被就业和谐成就业
  • 将字符串中出现的"????:“转换成"V”;

字符串会依次运用这三条规则,对字符串进行处理,每个规则都有自己需要完成的责任和任务。

第一步:定义封装请求的类Request和封装处理结果响应的类Response

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:16
 *
 * 封装请求的类Request
 */
public class Request {

    String requestStr;

    public String getRequestStr() {
        return requestStr;
    }

    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }

}
package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:18
 *
 * 封装响应信息的类Response
 */
public class Response {

    String responseStr;

    public String getResponseStr() {
        return responseStr;
    }

    public void setResponseStr(String responseStr) {
        this.responseStr = responseStr;
    }

}

第二步:定义具有过滤功能的接口Filter,具体的过滤规则需要实现该接口

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:20
 *
 * 定义接口Filter,具体的过滤规则需要实现这个接口,最后一个参数添加的意义是我们在Main函数中:
 * fc.doFilter(request, response,fc);
 * 执行这一步的时候可以按照规则链条一次使用三个过滤规则对字符串进行处理
 */
public interface Filter {

    void doFilter(Request request, Response response, FilterChain chain);

}

第三步:定义具体的过滤处理规则

规则一

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:22
 *
 * 处理字符串中的HTML标记
 */
public class HTMLFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        //将字符串中出现的"<>"符号替换成"[]"
        request.requestStr = request.requestStr.replace("<","[").replace(">","]") +
        //后面添加的是便于我们观察代码执行步骤的字符串
        "---HTMLFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---HTMLFilter()";
    }
}

规则二

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:26
 */
public class SensitiveFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        //处理字符串中的敏感信息,将被就业和谐成就业
        request.requestStr = request.requestStr.replace("被就业","就业").replace("敏感","") +
        //后面添加的是便于我们观察代码执行步骤的字符串
        "---sensitiveFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---sensitiveFilter()";
    }
}

规则三

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:29
 */
public class FaceFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        //将字符串中出现的":):"转换成"^V^";
        request.requestStr = request.requestStr.replace(":):","^V^")
        //后面添加的是便于我们观察代码执行步骤的字符串
        + "---FaceFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---FaceFilter()";
    }
}

第四步:定义责任链FilterChain

package com.test.filter;

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

/**
 * @author riemann
 * @date 2019/04/14 21:22
 *
 * 过滤链条
 */
public class FilterChain implements Filter{
    //用List集合来存储过滤规则
     List<Filter> filters = new ArrayList<Filter>();
    //用于标记规则的引用顺序
    int index = 0;
    //往规则链条中添加规则
    public FilterChain addFilter(Filter f) {
        filters.add(f);
        //代码的设计技巧:Chain链添加过滤规则结束后返回添加后的Chain,方便我们下面doFilter函数的操作
        return this;
    }
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        //index初始化为0,filters.size()为3,不会执行return操作
        if (index == filters.size()) {
            return;
        }
        //每添加一个过滤规则,index自增1
        Filter f = filters.get(index);
        index++;
        //根据索引值获取对应的规律规则对字符串进行处理
        f.doFilter(request, response, chain);
    }
}

第五步:测试一下我们的代码

package com.test.filter;

/**
 * @author riemann
 * @date 2019/04/14 21:44
 *
 * 责任链模式:
 * 数据消息在进入数据库之前,要被多种过滤规则进行处理,多种规则形成一种链,依次处理给定的数据消息
 */
public class Main {
    public static void main(String[] args) {
        //设定过滤规则,对msg字符串进行过滤处理
        String msg = ":):,<script>,敏感,被就业,网络授课";
        //过滤请求
        Request request = new Request();
        //set方法,将待处理字符串传递进去
        request.setRequestStr(msg);
        //处理过程结束,给出的响应
        Response response = new Response();
        //设置响应信息
        response.setResponseStr("response:");
        //FilterChain,过滤规则形成的拦截链条
        FilterChain fc = new FilterChain();
        //规则链条添加过滤规则,采用的是链式调用
        fc.addFilter(new HTMLFilter())
                .addFilter(new SensitiveFilter())
                .addFilter(new FaceFilter());
        //按照FilterChain的规则顺序,依次应用过滤规则
        fc.doFilter(request, response, fc);
        //打印请求信息
        System.out.println(request.getRequestStr());
        //打印响应信息
        System.out.println(response.getResponseStr());
    }
}

运行结果:

^V^,[script],,就业,网络授课---HTMLFilter()---sensitiveFilter()---FaceFilter()
response:---FaceFilter()---sensitiveFilter()---HTMLFilter()

现在执行到if判断,index的值为3,满足判断条件返回,上图中最上面的函数退栈,回到FaceFilter.doFilter函数中执行response.responseStr += “—FaceFilter()”;这就是我们运行结果中response中的第一部分。函数会依次退栈,response不断添加已经做过处理的规则的信息response.responseStr+="—sensitiveFilter()";response.responseStr+="—HTMLFilter()";最终回到Main.main函中打印reponse信息

运行过程用下图表示:

JAVA设计模式之(十七)责任链模式