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

浅谈责任链模式

作者: 程序员阿兵 | 来源:发表于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