美文网首页
浅谈责任链模式

浅谈责任链模式

作者: 程序员阿兵 | 来源:发表于2019-08-21 13:05 被阅读0次

责任链模式(Chain of Responsibility Pattern)

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

  • 责任链模式的重点在“链上”,由一条链去处理相似的请求,在链中决定谁来处理这个请求,并返回相应的结果。

演示代码

  • 新建几个任务,每个任务执行不同的需要 分别为 task1 task2 ...
public class Task1 extends BaseTask {

   public Task1(boolean isTask) {
       super(isTask);
   }

   @Override
   public void doAction() {
       // // 执行 子节点 链条断
       System.out.println("Task1 任务节点一 执行了");
   }
}
  • 每个任务继承父类
public abstract class BaseTask {

   // 判断当前任务节点 有没有能力执行  有
   private boolean isTask;

   public BaseTask(boolean isTask) {
       this.isTask = isTask;
   }

   // 执行下一个节点
   private BaseTask nextTask; // t2,t3,t4

   // 添加下一个节点任务
   public void addNextTask(BaseTask nextTask) {
       this.nextTask = nextTask;
   }

   // 让子节点任务去完成的
   public abstract void doAction();

   public void action() { // t1=false,t2=false,t3=true,
       if (isTask) { // t3
           doAction(); // 执行 子节点 链条断
       } else {
           // 继续执行下一个 任务节点
           if (nextTask != null) nextTask.action();
       }
   }
}

  • 执行所以的任务
        Task1 task1 = new Task1(false);
        Task2 task2 = new Task2(false);
        Task3 task3 = new Task3(true);
        Task4 task4 = new Task4(false);
        task1.addNextTask(task2);
        task2.addNextTask(task3);
        task3.addNextTask(task4);

        // 执行第一个任务节点
        task1.action();

由上面的代码可以,在task1 执行action时,addNextTask会传人下个任务,只有在当前的任务满足条件时会处理任务。

在翻阅okhttp的源码时,会发现在返回response时就是用到责任链模式:

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

将所有的拦截器缓存加入到RealInterceptorChain中,下面可以看到 RealInterceptorChain父类proceed方法:

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }
}

在上面方法中会发现又重新new 了RealInterceptorChain不同的是 传人的index由第一次0改变为index++模式,每次取出数组中不同的拦截器去执行,当拦截器处理完并且不需要走向下一步,可以直接返回最终response!

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

根据okhttp的责任链模式,可以对应去优化自己实现:

  • 第一步依然是第一父类任务:

public interface IBaseTask {

    /**
     * 参数一:任务节点是否有能力执行
     * 参数二:下一个任务节点
     * @param isTask
     */
    public void doRunAction(String isTask, IBaseTask iBaseTask);

}
  • 不同任务 task1 2 3....
public class Task1 implements IBaseTask {

    @Override
    public void doRunAction(String isTask, IBaseTask iBaseTask) { // iBaseTask == ChainManager
        if ("no".equals(isTask)) {
            System.out.println("拦截器 任务节点一 处理了...");
            return;
        } else {
            // 继续执行下一个链条的任务节点  ChainManager.doRunAction("ok", ChainManager)
            // ChainManager.doRunAction
            iBaseTask.doRunAction(isTask, iBaseTask);
        }
    }
}

  • 根据 okhttp RealInterceptorChain 的思想,可以将所有的任务缓存起来
public class ChainManager implements IBaseTask {

    private List<IBaseTask> iBaseTaskList = new ArrayList<>();

    public void addTask(IBaseTask iBaseTask) {
        iBaseTaskList.add(iBaseTask);
    }

    private int index = 0;

    @Override
    public void doRunAction(String isTask, IBaseTask iBaseTask) {
        if (iBaseTaskList.isEmpty()) {
            // 抛出异常..
            return;
        }

        if (index == iBaseTaskList.size() || index > iBaseTaskList.size()) {
            return;
        }

        IBaseTask iBaseTaskResult = iBaseTaskList.get(index); // index 0 t1,    index 1 t2      index 2 t3

        index ++;

        // iBaseTaskResult本质==Task1,   iBaseTaskResult本质==Task2      iBaseTaskResult本质==Task3
        iBaseTaskResult.doRunAction(isTask, iBaseTask);


    }
}

  • 调用
public class Test {

    public static void main(String[] args) {

        ChainManager chainManager = new ChainManager();

        chainManager.addTask(new Task1());
        chainManager.addTask(new Task2());
        chainManager.addTask(new Task3());

        chainManager.doRunAction("ok", chainManager);

    }

}

这样就和okhttp责任链模式神似了,唯一区别是我将chainManager也就是RealInterceptorChain 对象之前传传入调用当前任务,在内部改变index,而okhttp的思想是每次执行任务会重新new RealInterceptorChain(index),效果都是一样。

相关文章

网友评论

      本文标题:浅谈责任链模式

      本文链接:https://www.haomeiwen.com/subject/dzjbsctx.html