流行框架源码分析(13)-责任链设计模式

作者: ZJ_Rocky | 来源:发表于2017-10-26 16:46 被阅读96次

    主目录见:Android高级进阶知识(这是总目录索引)
     学习设计模式,个人觉得第一就是不能局限于一个思维,也许些许的变化有时能让它更加符合你的设计,所以我们不要拘泥于固定的角色,生搬硬套的场景,我们要经得起变化。这也是为什么会有那么多的变形的原因。我们今天要讲责任链设计模式(chain of responsibility),这个模式也是会有很多的变形,我们待会会在分析例子的过程中讲到。我们先来看下它的定义:

    责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

    这个定义非常明确地说明了责任链模式的作用,很多对象由每一个对象对其下家的引用而连接起来形成一条链也就是说请求向上传递过程中,如果自己不处理的话,那么由于自己持有了下家的引用,所以可以交给下家去处理,这样循环下去直到有对象想要处理。我们接着来看看UML类图:


    责任链设计模式

    角色介绍:

    • Handler:抽象处理者,声明一个请求的处理方法,并保持对下一个处理节点Handler对象的引用。

    • ConcreteHandler:具体处理者,对请求进行处理,如果不处理就讲请求转发给下一个节点上的处理对象。

    一.目标

    讲这个设计模式,是觉得他用的地方还是蛮广的,而且我们最熟悉的事件分发应该就是典型的责任链设计模式吧,所以我们今天目标也是:
    1.明白责任链设计模式怎么使用;
    2.知道在什么场景需要用到责任链设计模式。

    二.模式分析

    同样地,我们今天也先假设一个场景,公司有一天安排你去出差,那你说我要申请费用500块,然后你申请表就提交给组长,组长说数额太大不归我管,让主管来吧,主管也说这个我也不能管,让经理来吧,经理一甩手,允许了,然后你就拿着钱屁颠屁颠出差去了。这里我们首先看看我们抽象处理者角色:

    public abstract class Handler {
        protected int expenses;
        protected Handler mNextChain;
        
        public Handler(int expenses){
            this.expenses = expenses;
        }
        
        public void setNextHandler(Handler handler){
            this.mNextChain = handler;
        }
        
        public abstract void handleRequest(Request request);
    }
    

    我们看到这是一个典型的抽象处理者角色,里面有设置下家的引用setNextHandler(),还有处理条件expenses,处理方法handleRequest()。然后我们分别来看几个具体的处理者角色首先是组长:

    public class TeamLeader extends Handler{
        
        public TeamLeader() {
            super(200);
        }
    
        @Override
        public void handleRequest(Request request) {
            
            if (request.getApplyExpense() > this.expenses&& mNextChain != null) {
                this.mNextChain.handleRequest(request);
            }else{
                System.out.println("组长批准了");
            }
        }
    }
    

    我们看到这里处理条件传进去200,说明我只能处理两百块的出差申请,然后如果费用太高只能让上面的人来审批,当然这里判断不充分,但是anyway,我们只要了解思想即可。接着我们看下一个处理者:

    public class ApartmentDirector extends Handler{
    
        public ApartmentDirector() {
            super(400);
        }
    
        @Override
        public void handleRequest(Request request) {
            if (request.getApplyExpense() > this.expenses && mNextChain != null) {
                this.mNextChain.handleRequest(request);
            }else{
                System.out.println("主管批准了");
            }
        }
    }
    

    我们看到这里的处理条件是400,接着我们看下一个处理者:

    public class ApartmentManager extends Handler{
    
        public ApartmentManager() {
            super(500);
        }
    
        @Override
        public void handleRequest(Request request) {
            if (request.getApplyExpense() > this.expenses) {
                //this.mNextChain.handleRequest(request);
                System.out.println("不符合公司规定");
            }else{
                System.out.println("经理批准了");
            }
        }
    }
    

    到这里我们所有的处理者都已经出现了,接着就是我们的请求对象了。我们同样建一个请求者的抽象角色:

    public abstract class Request {
        public int requestExpense;
        
        public Request(int expense){
            this.requestExpense = expense;
        }
        
        public int getApplyExpense(){
            return this.requestExpense;
        }
    }
    

    然后建一个具体的请求者角色:

    public class BusinessRequest extends Request{
    
        public BusinessRequest() {
            super(500);
        }
    }
    

    到这里我们所有的角色都已经完成了,我们看下我们这个责任链是怎么使用的:

            Handler teamLeader = new TeamLeader();
            Handler apartmentDirector = new ApartmentDirector();
            Handler apartmentManager = new ApartmentManager();
            //设置链式关系
            teamLeader.setNextHandler(apartmentDirector);
            apartmentDirector.setNextHandler(apartmentManager);
            
            //请求事件
            Request request = new BusinessRequest();
            //处理请求
            teamLeader.handleRequest(request);
    

    我们看到我们请求传到这条链式调用关系上面去,然后根据申请的费用额度每个经理人会判断是否处理。但是这里有个问题,我们不能得到下家的反馈,也许我们需要对下家反馈做一个再处理呢?那么我们这里把这个变型一下。

    1.改版后的责任链设计模式

    我们首先来看抽象处理者。

    public abstract class Handler {
        protected int expenses;
        protected Handler mNextChain;
        
        public Handler(int expenses){
            this.expenses = expenses;
        }
        
        public void setNextHandler(Handler handler){
            this.mNextChain = handler;
        }
        
        public abstract String handleRequest(Request request);
    }
    

    我们看到这里唯一的不同是我们这里handleRequest()方法增加了String返回值表示我们的处理返回值。然后我们先来看看组长角色:

    public class TeamLeader extends Handler{
        
        public TeamLeader() {
            super(200);
        }
    
        @Override
        public String handleRequest(Request request) {
            
            if (request.getApplyExpense() > this.expenses&& mNextChain != null) {
                String response = this.mNextChain.handleRequest(request);
                if ("不符合公司规定".equalsIgnoreCase(response)) {
                    return "先给你批准"+this.expenses;
                }else{
                    return response;
                }
            }else{
                return "组长批准了";
            }
        }
    }
    

    我们看到了,这里针对下家处理返回的值还进行了处理,也就是说我们每一个节点都可以针对这个进行处理包装和返回结果。达到了功能增强的作用。另外两个节点也是类似,我就不具体贴出来代码了,之所以讲这个是因为我们OkHttp中用的责任链设计模式就是我们改版的模型。我们直接来欣赏下吧。

    2.OkHttp中的责任链设计模式

    我们上次已经说过了OkHttp的源码了,如果有兴趣可以看OkHttp源码分析,这里我们先来贴一张原理图:

    OkHttp流程图
    我们知道非常关键的地方就是一系列的拦截器,每个拦截器负责不同的功能,然后针对下个拦截器的返回reponse进行再处理。首先我们来看抽象处理者角色:
    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
    
        Response proceed(Request request) throws IOException;
    //省略一些跟讲解无关代码
    ......
      }
    }
    

    我们看到proceed方法就是我们这里传递处理的方法。然后程序会讲实现了Interceptor接口的拦截器添加到拦截器集合里面:

      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的里面会调用proceed进行拦截器里面方法的调用:

      // 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);
    

    然后我们看到拦截器(也就是我们具体处理者角色),这里面的代码,首先我们看第一个拦截器retryAndFollowUpInterceptor拦截器:

    @Override public Response intercept(Chain chain) throws IOException {
    .....
      try {
            response = realChain.proceed(request, streamAllocation, null, null);
            releaseConnection = false;
          } catch (RouteException e) {
    ....
          } catch (IOException e) {
    ....
            } finally {
    ....
             }
    .......
    }
    

    我们看到这里的proceed方法又交给了下个拦截器处理,那么我们来看下个拦截器BridgeInterceptor:

     @Override public Response intercept(Chain chain) throws IOException {
    ....
      Response networkResponse = chain.proceed(requestBuilder.build());
    
        HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    
        Response.Builder responseBuilder = networkResponse.newBuilder()
            .request(userRequest);
    ......
     return responseBuilder.build();
      }
    

    我们看到这个拦截器也调用了proceed方法把请求提交给下个拦截器,以此类推,下面的拦截器都是有这个操作,直到最后一个拦截器把结果返回,然后才会一级一级回归到第一个拦截器,然后对结果进行再处理,这里的第一个拦截器就是执行的重新请求等一些处理的。
    总结:所以我们看到责任链设计模式不仅可以针对链式中每个节点处理结果进行增强(OkHttp中的拦截器),而且可以针对请求进行截断(事件分发机制),可想而知,这个设计模式使用还是非常广泛的,希望这里说的有什么不足大家可以提出来。

    相关文章

      网友评论

        本文标题:流行框架源码分析(13)-责任链设计模式

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