「设计模式(四) - 责任链模式」

本文详细介绍了责任链模式,强调了其在降低请求者与处理者耦合中的作用。通过OkHttp的实际应用,展示了责任链模式如何工作,如通过Interceptor链处理网络请求。文中还探讨了OkHttp中的Dispatcher、AsyncCall以及各个拦截器的作用,并分析了责任链模式的优点和潜在问题。最后,提到了责任链模式适用于处理多个对象可能处理同一请求的情况,以及在Android面试中的重要性。
摘要由CSDN通过智能技术生成
一、能力越大责任越大

顾名思义,“责任链”就像是一根链条串联起来的一系列操作,每个操作都息息相关。请假的审批流程,报销流程等等依据不同职位对应的人员完成相应的审批操作;可以说是层层推进的。而我们最终关心的结果就是同意或者驳回。

二、责任链模式 Chain of Responsibility

当请求端Client发出请求时,为了降低请求者Client与处理对象们Handlers之间的耦合;同时满足众多Handlers都能有机会参与到对请求的处理,将Handler对象组成一条链。而请求随着链不断传递,直到被处理并返回结果。

三、组成部分

通过定义可以发现,责任链主要有几个组成部分:

  • 客户端请求类Client:发起请求,相当于开启责任链,提交任务到责任链等待处理结果。
  • 处理类的抽象接口Handler或者抽象类:包含处理请求方法的定义,通常也包含后继链指向。
  • 具体的Handler的实现类ConcreteHandler:根据自身能力的大小对Client的请求的具体实现,有可能刚好匹配那么直接处理返回结果链的调用结束,否则将请求转发到后继链继续处理直到请求处理完成。
  • 结构图如下:

责任链模式.png

四、简单的代码实现
1.设计一个文件的解析系统

文件解析的系统根据导入的文件格式,匹配不同的解析对象Handler对其进行解析,通过链的开启,有可能第一次就匹配到合适的类那么链的调用结束并返回结果;当然如果是不支持的的文件类型-那么作为程序设计时是不是就可以简单的转化为当前对象无法处理这个请求,并且没有后续Handler,通俗的讲即此时请求到链尾且仍没有合适的Handler能够处理,则调用结束给出相应的报错信息或者其他操作反馈到请求者Client

  • 抽象的处理类Handler
/**
 * Created by Sai
 * on: 12/01/2022 23:53.
 * Description:
 */
public abstract class FileParser {
  //后继链
  private FileParser next;

  public void setNext(FileParser next) {
    this.next = next;
  }
  //文件的扩展信息
  protected abstract String getExtension();
  
  protected abstract void doParse(String fileName);

  public void read(String fileName) {
    if (fileName.endsWith(getExtension())) {
      this.doParse(fileName);
      return;
    }

    if (next != null) next.read(fileName);
    else System.out.println("the file type " + fileName + " is unsupported ");
  }
} 

具体的文件解析实现类、如ExcelMarkDownWord三个组成一条责任链。

  • Excle文件解析类
/**
 * Created by Sai
 * on: 12/01/2022 00:01.
 * Description:
 */
public class ExcelParser extends FileParser {
  @Override
  protected String getExtension() {
    return ".xls";
  }

  @Override
  protected void doParse(String fileName) {
    System.out.println("Parse the excel file...... ");
    System.out.println("-------------------------------------->");
  }
} 
  • MarkDown文件解析具体实现类
/**
 * Created by Sai
 * on: 12/01/2022 00:03.
 * Description:
 */
public class MarkDownParser extends FileParser {
  @Override
  protected String getExtension() {
    return ".md";
  }

  @Override
  protected void doParse(String fileName) {
    System.out.println("Parse the markdown file......");
    System.out.println("---------------------------------------->");
  }
} 
  • Word文件解析具体实现类
/**
 * Created by Sai
 * on: 12/01/2022 00:10.
 * Description:
 */
public class WordParser extends FileParser {
    @Override
    protected String getExtension() {
        return ".doc";
    }

    @Override
    protected void doParse(String fileName) {
        System.out.println("Parse the word file......");
        System.out.println("----------------------------------->");
    }
} 

当然如果确定Client的请求比较明确,像此“文件”解析的系统,只需要导入文件,那么对于链的开启可以单独抽取出来。

  • 实现解析工具类
/**
 * Created by Sai
 * on: 12/01/2022 00:13.
 * Description:
 */
public class FileParserFactory {

  public static FileParser getDataReaderChain() {
    var excelParser = new ExcelParser();
    var markDownParser = new MarkDownParser();
    var wordParser = new WordParser();

    wordParser.setNext(markDownParser);
    markDownParser.setNext(excelParser);
    return wordParser;
  }
} 
  • Client测试类
/**
 * Created by Sai
 * on: 12/01/2022 00:15.
 * Description:
 */
public class Demo {

    public static void show() {
        var reader = FileParserFactory.getDataReaderChain();
        reader.read("file.xls");
        reader.read("file.md");
        reader.read("file.doc");
        reader.read("file.jpg");
    }

    public static void main(String[] args) {
        show();
    }
} 
  • 打印信息,显然对于JPG格式系统是不支持,那么也给到了Client相应的反馈信息
Parse the excel file...... 
success...... 
-------------------------------------->
Parse the markdown file......
success...... 
---------------------------------------->
Parse the word file......
success...... 
----------------------------------->
the file type file.jpg is unsupported, failed 

Process finished with exit code 0 
2.简单的总结

Client作为请求发起者,如导入文件并解析出想要得到的结果。与处理类之间耦合程度低,Client端只管文件的导入,并不会关心最终由谁来处理。即使系统以后需要扩展新的解析类也是非常方便的,只需要继承Handler并单独实现具体细节即可,比较易于扩展的。但是同样也会伴随着系统的膨胀,跟职责的粒度有关。另外观察也可发现,如果责任链太过于长的话,调用栈势必会很深。系统的性能也会打折扣,当然这也是根据具体的业务具体来考虑的。该用的时候想好怎么用,不该用的时候没必要为了设计而设计。毕竟设计模式本质仅仅是为了降低复杂度,降低耦合提高扩展性为目标。

  • Client请求端与处理端Handler耦合度低
  • 职责的分配可以根据业务需求灵活组合,而修改某一具体职责实现细节不影响整体系统的稳定。
  • 易于扩展。

当然缺点也是存在的

  • 当职责的增加,链的长度增加,调用栈深度加深则会影响系统的效率。
  • 职责的具体实现类如果较多,增加了一定的维护成本,同时Client端开启链时复杂度提高。
五、okHttp中的责任链模式

早期Java版本,okHttp3最新的版本为4.9.3,不知道从哪个版本起已经改为Kotlin实现,实现细节作出了调整,但对于拦截器责任链的主要流程变动很小。

  • OkHttpClient相当于我们网络的配置控制中心,包括一些基础的配置,连接池、重试、桥接、协议等,主要配置:Dispatcher(线程调度)设定了最大请求数,单个Host的最大请求数。Protocols支持的协议,HTTP/1.1、HTTP/2。ConnectionSpec对于Socket的设置信息,明确是明文传输的HTTP,还是TLS的HTTPS。 Interceptor,核心链,包含了几个重要的拦截器。当然还包括其他的一些基础参数。
1.newCall

从实际运用的例子入手:

private static void connectNet() {
       OkHttpClient client = new OkHttpClient();
       Request request = new Request.Builder()
               .url("https://www.baidu.com")
               .build();
        //异步请求 
       client.newCall(request).enqueue(new Callback() {
           @Override
           public void onFailure(Call call, IOException e) {
               System.out.println("Failed----->" + e.getMessage());
           }

           @Override
           public void onResponse(Call call, Response response) throws IOException {
               System.out.println("Success----->" + response.toString());
           }
       });
   } 

newCall(request)方法返回的是一个RealCall对象,实现了Call的接口,当调用RealCall.execute()时:

RealCall.getResponseWithInterceptorChain()会被调用,发起网络请求并拿到返回的响应值R

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值