责任链模式

157 阅读3分钟

责任链模式

责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一个链,并沿着这个链传递这个请求,直到有一个对象处理它。【DP】

客户端来定义链的结构,随时增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性。[DP]

设计模式中有一个很经典又常用的模式即责任链模式,我们来仔细学习一下:

  • 常见责任链模式
  • okhttp责任链实现

常见责任链模式

以下例子来自w3cschool实现:

public class Request {
    String level;
    public Request(String level){
        this.level = level;
    }
​
    public String getLevel(){
        return level;
    }
}
​
public class Response {
}
​
public abstract class Handler {
    private Handler nextHandler;
    public final Response handleRequest(Request request){
        Response response = null;
​
        if(this.getHandlerLevel().equals(request.getLevel())){
            response = this.response(request);
        }else{
            if(this.nextHandler != null){
                response = this.nextHandler.handleRequest(request);
            }else{
                System.out.println("-----没有合适的处理器-----");
            }
        }
        return response;
    }
    public void setNextHandler(Handler handler){
        this.nextHandler = handler;
    }
    protected abstract String getHandlerLevel();
    public abstract Response response(Request request);
}
​
public class ConcreteHandler1 extends Handler {
    @Override
    protected String getHandlerLevel() {
        return "1";
    }
​
    @Override
    public Response response(Request request) {
        System.out.println("-----请求由处理器1进行处理-----");
        return new Response();
    }
}
​
public class ConcreteHandler2 extends Handler {
    @Override
    protected String getHandlerLevel() {
        return "2";
    }
​
    @Override
    public Response response(Request request) {
        System.out.println("-----请求由处理器2进行处理-----");
        return new Response();
    }
}
​
public class ConcreteHandler3 extends Handler {
    @Override
    protected String getHandlerLevel() {
        return "3";
    }
​
    @Override
    public Response response(Request request) {
        System.out.println("-----请求由处理器3进行处理-----");
        return new Response();
    }
}
​
public class Client {
    public static void main(String[] args){
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
​
        handler1.setNextHandler(handler2);
        handler2.setNextHandler(handler3);
​
        Response response = handler1.handleRequest(new Request("3"));
    }
}

okhttp责任链实现(简化版)

以下代码来自okhttp源码,经过简化后得到的:

public class Request {
​
}
​
public class Response {
​
}
​
public interface Interceptor {
​
    Response intercept(Chain chain) throws IOException;
​
    interface Chain {
​
        Request request();
​
        Response proceed(Request request) throws IOException;
    }
}
​
public final class ConnectInterceptor implements Interceptor {
​
    public ConnectInterceptor() {
    }
​
    @Override
    public Response intercept(Chain chain) throws IOException {
        System.out.println("ConnectInterceptor");
        return chain.proceed(chain.request());
    }
}
​
public final class CallServerInterceptor implements Interceptor {
​
    @Override
    public Response intercept(Chain chain) throws IOException {
        System.out.println("CallServerInterceptor");
        return new Response();
    }
}
​
public final class RealInterceptorChain implements Interceptor.Chain {
​
    private final List<Interceptor> interceptors;
    private final int index;
    private final Request request;
​
    public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) {
        this.interceptors = interceptors;
        this.index = index;
        this.request = request;
    }
​
    @Override
    public Request request() {
        return request;
    }
​
    @Override
    public Response proceed(Request request) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
​
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors,index + 1, request);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
​
        // Confirm that the intercepted response isn't null.
        if (response == null) {
            throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
​
        return response;
    }
​
}
​
public class Client {
    public static void main(String[] args) throws IOException {
​
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(new ConnectInterceptor());
        interceptors.add(new CallServerInterceptor());
​
        Request originalRequest = new Request();
        Interceptor.Chain chain = new RealInterceptorChain(interceptors,0,originalRequest);
        Response response = chain.proceed(originalRequest);
​
    }
}

说明:okhttp真实源码(本文中已经省略了)中CallServerInterceptor间接依赖于ConnectInterceptor产生的exchange,真实实现是非标准的。

后记

责任链模式是不分标准和非标准的,我自己定义了标准实现,其它是变种:

  • request没有在链式处理中变更
  • 有且一定仅有一个对象处理请求
  • 链式路径是链式,不是树形或者其它数据结构,换句话说在链式处理中除开抛异常和直接返回,没有改变流程即新建分支流程
  • 链式处理器对象之间没有直接或间接依赖

思考:

  • 责任链模式处理时request可以改变吗?
  • 链式数据结构可以是其它吗?
  • 链式流程分支可以改变吗?
  • 对于request请求可以多对象处理吗?
  • 链式处理器可以相互依赖吗?
  • 一定要在客户端(使用时)定义链吗?

代码上实现思考中提到的问题很简单,然而带来好处的同时也会产生各种副作用,大家可以思考一下,根据实际情况选用。一般框架中用到的都是标准实现的变种,也就是非标准实现,后面如果碰到其它框架责任链模式,在补充一下。

这里声明一下:标准实现和非标准实现都有各自的优劣势,请根据实际情况选择。

本文参考了以下文档:

  • w3cschool
  • 《设计模式:可复用面向对象软件的基础》【DP】
  • 《设计模式之禅》
  • 《大话设计模式》