责任链模式,做个东西我们可能自己虽然没有亲手动手写过类似的代码,但是在实际的码农生涯中肯定是有过类似的接触的,特别是Java Web的开发者,比如什么Filter,拦截器,多个AOP形成的拦截器链肯定会遇到一个你希望一步步的走下去的,多个人按照顺序的执行。

  • 责任链的图
    责任链模式_简单模拟
  • 看图知道有啥特点:父类Handler的实现类中,有个和自身相同类的组合实例,通过实例就可以不断的一个接一个处理HandleProcess方法。说起来不是特别的好懂,看代码。

    简单的责任链模式

  • Handler
/**
 * descrption: 创建责任链模式
 * authohr: wangji
 * date: 2017-09-23 9:36
 */
public abstract  class Handler {

    private Handler sucessor;//接班人

    public void setSucessor(Handler sucessor) {
        this.sucessor = sucessor;
    }
    /**
     * @desction: 1.首先执行自身的;2.然后调用责任链中的下一个继承者
     * @author: wangji
     * @date: 2017/9/23
     * @param:
     * @return:
     */
    public void execute(){
        handleProcess();
        if(sucessor != null){
            sucessor.execute();
        }
    }
    protected abstract void handleProcess();
}
  • Handler的实现A
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ConcreteHandlerA extends Handler {
    @Override
    protected void handleProcess() {
        log.info("handle by ConcreteHandlerA");
    }
}
  • Client的实现,看看效果
/**
 * descrption: 创建和调用责任链
 * authohr: wangji
 * date: 2017-09-23 9:45
 */
public class Client {
    public static void main(String[] args) {
        ConcreteHandlerA ConcreteHandlerA = new ConcreteHandlerA();
        ConcreteHandlerB ConcreteHandlerB = new ConcreteHandlerB();
        ConcreteHandlerC ConcreteHandlerC = new ConcreteHandlerC();
        //A->B-C
        ConcreteHandlerA.setSucessor(ConcreteHandlerB);
        ConcreteHandlerB.setSucessor(ConcreteHandlerC);
        ConcreteHandlerA.execute();
        //这里比较的麻烦,每次都是需要依次的处理一个个后继

    }
}
//2017-09-23 11:29:33,027  INFO [ConcreteHandlerA.java:9] : handle by ConcreteHandlerA
//2017-09-23 11:29:33,030  INFO [ConcreteHandlerB.java:10] : handle by ConcreteHandlerB
//2017-09-23 11:29:33,031  INFO [ConcreteHandlerC.java:10] : handle by ConcreteHandlerC

但是上面的比较麻烦,每次都需要对下个执行者进行依次的设置其信息,不太舒服,进行改进一下比较好。将Handler的实现者保存到一个Chain中的成员变量的List中,每次每个Handler的实现者都有Chain的引用,这样就可以通过改变下标,依次的执行。可能不太好理解,看看代码就懂了。

  • ChainHandler
/**
 * descrption:通过传入Chain中保存了ChainHanler的List,然后遍历,通过下标标识。由于有Chain的对象,可以调用其方法
 * authohr: wangji
 * date: 2017-09-23 9:55
 */
public abstract class ChainHandler {

    public void execute(Chain chain){
        handleProcess();
        chain.proceed();
    }

    protected abstract void handleProcess();
}
  • ChainHandler的实现者
import lombok.extern.slf4j.Slf4j;

/**
 * descrption:
 * authohr: wangji
 * date: 2017-09-23 9:58
 */
@Slf4j
public class ConcreteHandlerA extends ChainHandler {
    protected void handleProcess() {
        log.info("handle by ConcreteHandlerA");
    }
}
  • 重点的Chain
import java.util.List;

/**
 * descrption: 责任链模式的升级处理,不要每次都去处理后继者
 * http://blog.csdn.net/justloveyou_/article/details/68491121
 * 这个博客自己手动写责任链模式有点类似
 * authohr: wangji
 * date: 2017-09-23 9:54
 */
public class Chain {
    private List<ChainHandler> handlers;

    private int index = 0;

    public Chain(List<ChainHandler> handlers) {
        this.handlers = handlers;
    }

    public void proceed(){
        if(index >= handlers.size()){
            return ;
        }
        handlers.get(index++).execute(this);
    }
}
  • Client的使用
/**
 * descrption:升级版Chain模式,不需要为每一个具体的实现确定一个下一继承者
 * authohr: wangji
 * date: 2017-09-23 10:32
 */
public class ChainClient {
    public static void main(String[] args) {
        //这里的处理也是一样的,只是不需要为每一个设置下一继承者,在确定List的时候就通过自身的下标确定了。
        List<ChainHandler> handlers = Arrays.asList(
                new ConcreteHandlerA(),
                new ConcreteHandlerB(),
                new ConcreteHandlerC()
        );
        Chain chain = new Chain(handlers);
        chain.proceed();
    }
}

实际场景的应用

参考文档实现原理
图:
责任链模式_简单模拟_02

  • Filter
/**
 * descrption:模拟Servlet的Filter
 * authohr: wangji
 * date: 2017-09-23 11:45
 */
public interface Filter {
    //每个Filter均为FilterChain的成员, Filter持有FilterChain的引用,以便调用链条中的各处理者
    void doFilter(Request request, Response response, FilterChain chain);
}
  • 实现Filter(替换我的名字)
import lombok.extern.slf4j.Slf4j;

/**
 * descrption: 简单的模拟过滤器替换一个姓名
 * authohr: wangji
 * date: 2017-09-23 13:23
 */
@Slf4j
public class ConcreteFileterA implements Filter {
    public void doFilter(Request request, Response response, FilterChain chain) {
        log.info("ConcreteFileterA replace  wangji to 汪吉 begin");
        String msg = request.getRequest().replace("wangji", "汪吉");
        request.setRequest(msg);
        chain.doFilter(request, response);
        response.setResponse(response.getResponse() + "--->replace  wangji to 汪吉");
        log.info("ConcreteFileterA replace  wangji to 汪吉 end");
    }
}
  • 添加一个字符串
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class ConcreteFileterB implements Filter {
    public void doFilter(Request request, Response response, FilterChain chain) {
        log.info("ConcreteFileterB add  String: \"add a String\"; begin");
        String msg = request.getRequest()+" add a String";
        request.setRequest(msg);
        chain.doFilter(request, response);
        response.setResponse(response.getResponse() + "--->add  String: \"add a String\";");
        log.info("ConcreteFileterB add  String: \"add a String\"; end");
    }
}
  • 重点的FilterChain和上面的升级的责任链模式类似
/**
 - descrption: 过滤链的抽象
 - authohr: wangji
 - date: 2017-09-23 11:44
 */
public class FilterChain {

    List<Filter> filters = new ArrayList<Filter>();
    int index = 0;

    // 链式编程
    public FilterChain addFilter(Filter filter){
        filters.add(filter);
        return this;
    }

    public void doFilter(Request request, Response response) {
        if(index == filters.size()) return;
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request, response, this);//拥有过滤链的抽象
    }
}
  • 简单模拟请求和返回内容
public class Request {

    // 请求消息
    private String request;

    public String getRequest() {
        return request;
    }

    public void setRequest(String request) {
        this.request = request;
    }

}

public class Response {

    // 响应消息
    private String response;

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

}
  • 测试模拟的
/**
 * descrption:测试模拟的Filter
 * authohr: wangji
 * date: 2017-09-23 13:31
 */
@Slf4j
public class Client {
    public static void main(String[] args) {
        ConcreteFileterA concreteFileterA = new ConcreteFileterA();
        ConcreteFileterB concreteFileterB = new ConcreteFileterB();
        FilterChain filterChain = new FilterChain();
        filterChain.addFilter(concreteFileterA)
                    .addFilter(concreteFileterB);

        // 待处理消息
        String msg = "This is an analog filter,my request msg is:wangji is a boy";
        Request request = new Request();
        request.setRequest(msg);

        Response response = new Response();
        response.setResponse("Response");

        filterChain.doFilter(request,response);

        log.info("file end request str:"+request.getRequest());
        log.info("file end reponse str:"+response.getResponse());
    }
}
//2017-09-23 13:37:54,551  INFO [ConcreteFileterA.java:13] : ConcreteFileterA replace  wangji to 汪吉 begin
//2017-09-23 13:37:54,554  INFO [ConcreteFileterB.java:9] : ConcreteFileterB add  String: "add a String"; begin
//2017-09-23 13:37:54,555  INFO [ConcreteFileterB.java:14] : ConcreteFileterB add  String: "add a String"; end
//2017-09-23 13:37:54,555  INFO [ConcreteFileterA.java:18] : ConcreteFileterA replace  wangji to 汪吉 end
//2017-09-23 13:37:54,555  INFO [Client.java:29] : file end request str:This is an analog filter,my request msg is:汪吉 is a boy add a String
//2017-09-23 13:37:54,556  INFO [Client.java:30] : file end reponse str:Response--->add  String: "add a String";--->replace  wangji to 汪吉