责任链模式

引入

我们知道, 命令模式可以将请求者和执行者解耦, 客户端需要知道命令的接受者(如:Tv), 在创建命令的时候就把接受者(电视)与命令绑定在一起发送给请求者(电视的遥控器); 现在在命令模式的基础上, 不关心具体的命令/请求执行者, 只是将封装后的命令交给职责链的头部而已, 这就引出职责链模式

  • 链是一系列节点的集合。
  • 链的各节点可灵活拆分再重组。

定义

为了避免请求的发送者和接收者之间的耦合关系,使多个接受对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

结构

代码分析

/**
 * 信息处理接口, 链条上的每个过滤器都实现它
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午5:45:12
 */
public interface IFilter {

    /**
     * 处理信息方法
     * @param rqt 输入
     * @return
     */
    String doFilter(String rqt);
}

/***
 * 职责链, 面向处理节点接口编程, 和具体的处理节点没有关系
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午6:24:56
 */
public class FilterChain implements IFilter {

    private List<IFilter> filterChain =  new ArrayList<IFilter>();

    @Override
    public String doFilter(String rqt) {
        for(IFilter f: filterChain) {
            rqt = f.doFilter(rqt);
        }
        return rqt;
    }

    /**
     * 添加过滤节点
     * @param filter
     * @return
     */
    public FilterChain addFilter(IFilter filter) {
        this.filterChain.add(filter);
        return this;
    }

}

/**
 * 信息处理器, 封装了职责链, 这里相当与一个外观模式, 封装了内部细节,只提供给外部一个process()
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午6:01:33
 */
@Data
public class MessageProcessor {

    /**
     * 封装的职责链
     */
    private FilterChain fc;
    public MessageProcessor(FilterChain fc) {
        this.fc = fc;
    }

    public String process(String rqt) {
        return fc.doFilter(rqt);
    }

}

/**
 * 具体的处理节点, 将<>替换为[]
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午6:11:58
 */
public class HtmlFilter implements IFilter {

    @Override
    public String doFilter(String rqt) {
        String replace = rqt.replaceAll("<", "[")
                .replaceAll(">", "]");
        return replace;

    }

}

/**
 * 具体的处理节点, 敏感词过滤 将xxx换为yyy
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午6:15:37
 */
public class SensitiveFilter implements IFilter {

    @Override
    public String doFilter(String rqt) {
        return rqt.replaceAll("xxx", "yyy");
    }

}

/**
 * 简单职责链模式client
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午6:17:51
 */
public class Client {

    public static void main(String[] args) {
        String str = "hhh, xxx :) <script>";
        FilterChain fc = new FilterChain().addFilter(new HtmlFilter()).addFilter(new SensitiveFilter());
        MessageProcessor processor = new MessageProcessor(fc);

        String rst = processor.process(str);
        System.out.println(rst);
    }
}

复杂(请求响应有序)责任链

类比 servlet 中的 filter

请求响应有序 类似这张示意图:

结构:

/**
 * request
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:09:54
 */
@Data
public class Request {

    private String content;
}

/**
 * response
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:10:24
 */
@Data
public class Response {

    private String content;
}

/**
 * 节点接口
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:08:13
 */
public interface IFilter {

    void doFilter(Request rqt, Response rsp, FilterChain chain);
}

/**
 * filter chain
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:20:58
 */
@Data
public class FilterChain implements IFilter {

    /**
     * 节点执行索引, 初始为0; 表示当前执行到哪个filter了
     */
    private int currentFilterIndex = 0;

    /**
     * 过滤节点容器
     */
    private List<IFilter> filters = new ArrayList<IFilter>();

    @Override
    public void doFilter(Request rqt, Response rsp, FilterChain chain) {
        // 当 chain 中的 filter 被遍历执行完, 跳出
        if (this.filters.size() == currentFilterIndex) {
            return;
        }
        else {
            IFilter filter = filters.get(currentFilterIndex);
            // 当前节点获取到后, 马上索引移动到下一个, 不然会循环调用, 一直调用第一个filter, 直到系统崩溃
            currentFilterIndex++;
            filter.doFilter(rqt, rsp, chain);
        }
    }

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

}

/**
 * html filter
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:32:39
 */
public class HtmlFilter implements IFilter {

    @Override
    public void doFilter(Request rqt, Response rsp, FilterChain chain) {
        rqt.setContent(
                rqt.getContent().replace("<", "[").replace(">", "]"));
        System.out.println("HtmlFilter: 请求过程中被处理");
        chain.doFilter(rqt, rsp, chain);
        System.out.println("HtmlFilter: 返回过程中被处理");
    }

}


/**
 * sensitive filter
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:38:58
 */
public class SensitiveFilter implements IFilter {

    @Override
    public void doFilter(Request rqt, Response rsp, FilterChain chain) {
        rqt.setContent(rqt.getContent().replaceAll("xxx", "yyy"));
        System.out.println("SensitiveFilter: 请求过程被处理");
        chain.doFilter(rqt, rsp, chain);
        System.out.println("SensitiveFilter: 返回过程被处理");
    }

}

/**
 * 测试
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月26日 下午8:43:43
 */
public class Client {

    public static void main(String[] args) {
        String str = "hhh, xxx :) <script>, ";
        Request rqt = new Request();
        rqt.setContent(str);
        Response rsp = new Response();
        rsp.setContent("response-content");

        FilterChain fc = new FilterChain().addFilter(new HtmlFilter()).addFilter(new SensitiveFilter());
        fc.doFilter(rqt, rsp, fc);
        System.out.println(rsp.getContent());
    }
}

模式分析

  • 各个处理节点有公共的接口
  • 可以做成"请求响应有序"的需求, 此时注意防止循环调用

实例

  • java.util.logging.Logger#log()
  • Apache Commons Chain
  • javax.servlet.Filter#doFilter()

results matching ""

    No results matching ""