天天看点

从Filter看责任链模式

模拟请求

一个Request类来模拟请求对象、一个Response类来模拟响应对象、一个APP类用来模拟请求处理的过程,可以认为是Servlet请求处理的一个简版

package com.seven.filter;

public class Request {

    /**
     * 请求数据
     */
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}
           
package com.seven.filter;


public class Response {

    /**
     * 响应数据
     */
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}
           
package com.seven.filter;

public class App {

    public static void main(String[] args) {

        Request request = new Request();
        Response response = process(request);
        System.out.println(response.getData());
    }


    /**
     * 模拟请求处理全过程
     *
     * @param request 请求对象【模拟HttpServletRequest对象】
     * @return Response 返回对象【模拟HttpServletResponse对象】
     */
    private static Response process(Request request) {
        Response response = new Response();
        response.setData("处理成功");
        return response;
    }

}
           

添加功能

  1. 新增参数校验,判断请求参数中是否包含test字符串,不包含的话直接处理失败
package com.seven.filter;

public class App {

    public static void main(String[] args) {

        Request request = new Request();
        Response response = process(request);
        System.out.println(response.getData());
    }


    /**
     * 模拟请求处理全过程
     *
     * @param request 请求对象【模拟HttpServletRequest对象】
     * @return Response 返回对象【模拟HttpServletResponse对象】
     */
    private static Response process(Request request) {
        Response response = new Response();
        if (request != null && request.getData() != null && request.getData().contains("test")) {
            response.setData("处理成功");
        }
        response.setData("处理失败");
        return response;
    }

}
           
  1. 新增日志功能,在请求处理前后添加日志
package com.seven.filter;

public class App {

    public static void main(String[] args) {

        Request request = new Request();
        Response response = process(request);

    }


    /**
     * 模拟请求处理全过程
     *
     * @param request 请求对象【模拟HttpServletRequest对象】
     * @return Response 返回对象【模拟HttpServletResponse对象】
     */
    private static Response process(Request request) {
        Response response = new Response();
        if (request != null && request.getData() != null && request.getData().contains("test")) {
            System.out.println("————————开始处理——————————");//模拟日志
            response.setData("处理成功");
            System.out.println("————————处理结束——————————");//模拟日志
        }
        response.setData("处理失败");
        return response;
    }

}
           

缺点

  1. 每次新加功能需要改动主方法,违反开闭原则,不易扩展
  2. 新增的参数校验、日志都不是主要业务逻辑,而却和主要业务代码耦合在一起,经常改动,风险较大

Filter 模式

先回忆下我们使用Filter的情况,Filter是针对请求的,一般是在请求处理前进行拦截,做一些比如统一编码、权限校验、日志记录等功能,我们下面就模拟权限校验(这里用参数检验代替)、日志记录这两项功能,使用Filter模式来模拟上面的功能实现,同时根据FilterChain,我们体会下责任链模式

package com.seven.filter;

public interface Filter {

    /**
     * 过滤器
     * @param request 请求对象
     * @param response 返回对象
     */
     void doFilter(Request request, Response response,FilterChain chain);
}
           
package com.seven.filter;

/**
 * 参数校验过滤器
 */
public class ParameterValidateFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response,FilterChain chain) {

        if (request != null && request.getData() != null && request.getData().contains("test")) {
            chain.doFilter(request,response,chain);
        }else {
            response.setData("处理失败");
        }
    }
}

           
package com.seven.filter;

/**
 * 日志过滤器
 */
public class LogFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        System.out.println("————————开始处理——————————");//模拟日志
        chain.doFilter(request, response, chain);
        System.out.println("————————处理结束——————————");//模拟日志
    }
}

           
package com.seven.filter;

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

/**
 * 过滤器链【执行责任链模式的主要成员】
 */
public class FilterChain  implements Filter{

    /**
     * 过滤器列表
     */
    private List<Filter> filters = new ArrayList<>();

    private int index=;

    /**
     * 添加过滤器
     * @param filter
     */
    public void addFilter(Filter filter) {
        filters.add(filter);
    }

    @Override
    public void doFilter(Request request, Response response,FilterChain chain) {
        if(index==filters.size()){
            /**
             * 真正处理请求
             */
            response.setData("处理成功");
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request,response,chain);
    }
}
           
package com.seven.filter;

public class App {

    public static void main(String[] args) {
        Request request = new Request();
        request.setData("test");
        process(request);

    }


    /**
     * 模拟请求处理全过程
     *
     * @param request 请求对象【模拟HttpServletRequest对象】
     * @return Response 返回对象【模拟HttpServletResponse对象】
     */
    private static Response process(Request request) {
        Response response = new Response();
        FilterChain chain = new FilterChain();
        chain.addFilter(new ParameterValidateFilter());
        chain.addFilter(new LogFilter());
        chain.doFilter(request, response, chain);
        return response;
    }

}
           
————————开始处理——————————
处理成功
————————处理结束——————————
           

总结

  1. Filter是针对请求进行拦截、意在请求前进行一些过滤、权限校验、日志记录、统一编码等
  2. 所有Filter统一在FilterChain中组成一个链条,然后调用也统一由FilterChain来协调,确保以链条的模式执行
  3. 责任链模式是一种重要的设计模式,如Servlet中的Filter模式、Mybatis中的Plugin模式等都是责任链模式的体现
从Filter看责任链模式

微信公众号:宋坤明

下面的是我的公众号二维码图片,欢迎关注。

从Filter看责任链模式