责任链模式

责任链模式

本文链接:https://blog.csdn.net/feather_wch/article/details/131760462

1、是一种行为型设计模式
2、主要角色

  1. 抽象处理者
  2. 具体处理者

3、允许将请求沿着一系列处理者进行传递,直到有一个处理者可以处理该请求

  1. 解耦请求 发送者 和 处理者
  2. 可以动态改变处理者链条的顺序和内容

4、在Java中,责任链模式有多种实现方式,例如:

  • 使用抽象处理者类和具体处理者类,每个处理者类都有一个指向下一个处理者的引用,以及一个抽象的处理请求的方法。这种方式可以实现灵活的链构建和动态地添加或删除处理者。²
  • 使用过滤器接口和过滤器链类,每个过滤器都实现了一个过滤方法,过滤器链类负责将过滤器串联起来,并提供一个执行过滤的方法。这种方式可以实现简单的责任链模式,常用于对请求进行预处理或后处理。³
  • 使用注解和反射机制,每个处理者都使用注解来标识自己的优先级或顺序,通过反射机制来获取所有的处理者并按照注解来排序,然后依次执行处理请求的方法。这种方式可以实现无侵入性的责任链模式,不需要修改原有的代码结构。

优点和缺点

责任链模式的优点有:

  • 请求与处理解耦,降低了系统的耦合度¹
  • 处理者只需要关心自己的处理逻辑,不需要知道链条的结构和其他处理者的情况²
  • 易于维护,可以灵活地增加或删除处理者,符合开闭原则³

责任链模式的缺点有:

  • 产生很多细粒度的对象,增加了系统的复杂度和开销¹
  • 不一定能处理请求,可能出现请求无人响应的情况,需要提供默认处理和检查链条的有效性⁴

实例:日志处理->抽象处理者类和具体处理者类

// 定义日志级别常量
public class LogLevel {
    public static final int INFO = 1;
    public static final int DEBUG = 2;
    public static final int ERROR = 3;
}

抽象处理者


// 定义抽象日志记录器类
public abstract class Logger {
    // 保存下一个日志记录器的引用
    protected Logger nextLogger;
    // 保存当前日志记录器的日志级别
    protected int level;

    // 设置下一个日志记录器
    public void setNextLogger(Logger nextLogger) {
        this.nextLogger = nextLogger;
    }

    // 处理日志请求
    public void logMessage(int level, String message) {
        // 如果当前日志记录器的级别大于等于请求的级别,则输出日志信息
        if (this.level <= level) {
            write(message);
        }
        // 如果存在下一个日志记录器,则传递给它继续处理
        if (nextLogger != null) {
            nextLogger.logMessage(level, message);
        }
    }

    // 抽象方法,由具体子类实现
    protected abstract void write(String message);
}

具体处理者

// 定义具体日志记录器类:控制台日志记录器
public class ConsoleLogger extends Logger {
    // 构造方法,设置当前日志记录器的级别为INFO
    public ConsoleLogger() {
        this.level = LogLevel.INFO;
    }

    // 实现write方法,输出到控制台
    @Override
    protected void write(String message) {
        System.out.println("Console Logger: " + message);
    }
}

// 定义具体日志记录器类:文件日志记录器
public class FileLogger extends Logger {
    // 构造方法,设置当前日志记录器的级别为DEBUG
    public FileLogger() {
        this.level = LogLevel.DEBUG;
    }

    // 实现write方法,输出到文件(这里简化为控制台)
    @Override
    protected void write(String message) {
        System.out.println("File Logger: " + message);
    }
}

// 定义具体日志记录器类:错误日志记录器
public class ErrorLogger extends Logger {
    // 构造方法,设置当前日志记录器的级别为ERROR
    public ErrorLogger() {
        this.level = LogLevel.ERROR;
    }

    // 实现write方法,输出到错误日志(这里简化为控制台)
    @Override
    protected void write(String message) {
        System.out.println("Error Logger: " + message);
    }
}

// 定义客户端类
public class Client {
    public static void main(String[] args) {
        // 创建各个日志记录器对象
        Logger consoleLogger = new ConsoleLogger();
        Logger fileLogger = new FileLogger();
        Logger errorLogger = new ErrorLogger();

        // 构建责任链,设置每个日志记录器的下一个日志记录器
        consoleLogger.setNextLogger(fileLogger);
        fileLogger.setNextLogger(errorLogger);

        // 发送不同级别的日志请求,观察输出结果
        consoleLogger.logMessage(LogLevel.INFO, "This is an information.");
        consoleLogger.logMessage(LogLevel.DEBUG, "This is a debug message.");
        consoleLogger.logMessage(LogLevel.ERROR, "This is an error message.");
    }
}

输出结果:

Console Logger: This is an information.
Console Logger: This is a debug message.
File Logger: This is a debug message.
Console Logger: This is an error message.
File Logger: This is an error message.
Error Logger: This is an error message.

从输出结果可以看出,每个日志记录器都会根据自己的级别来决定是否输出日志信息,并且会将请求传递给下一个日志记录器继续处理。这样就实现了责任链模式的功能。

实例二:

责任链和OkHttp

1、OkHttp采用的哪种责任链模式

  1. 采用的是不纯的责任链模式
  2. 每个拦截器都组装了响应的一部分

2、OkHttp定义了两个接口

  1. Interceptor:Response r = intercept(Chain c)
  2. Interceptor.Chain: Response r = intercept(Request q)
  3. 实现了Chain接口的内部类RealInterceptorChain

3、抽象处理者:Interceptor

  1. Interceptor接口中只有一个方法:intercept
  2. 接收一个Chain对象作为参数
  3. 返回一个Response对象作为结果。

4、具体处理者:每个实现了Interceptor接口的类都负责处理响应的一部分,并调用Chain对象的proceed方法来传递给下一个拦截器继续处理。

5、Chain接口中也只有一个方法:proceed

  1. 接收一个Request对象作为参数
  2. 返回一个Response对象作为结果
  3. Chain对象负责执行intercept方法,并维护当前拦截器的索引和列表。

4、RealInterceptorChain类是Chain接口的具体实现类,1. 包含了一个拦截器列表、一个网络连接对象、一个请求对象、一个响应对象、一个重试次数和一个索引。
2. 它在proceed方法中根据索引来获取当前拦截器
3. 并调用其intercept方法来处理请求和响应,并将自身作为参数传递给下一个拦截器。

5、OkHttp和责任链模式的总结

  1. Interceptor负责处理请求和响应的一部分
  2. Interceptor通过Chain.proceed()传递给下一个拦截器处理
  3. Chain会找到下一个拦截器,并且执行器intercept()方法

6、RealInterceptorChain是什么

  1. 内部维护了List interceptors
  2. proceed()方法中通过index找到下一个拦截器,并且执行其intercept()方法,返回其Response给上一层
  3. 用于用户拦截器和网络拦截器

OkHttp源码流程

6、OkHttp拦截器执行流程是指OkHttp如何通过一系列的拦截器来实现网络请求和响应的处理的过程。

拦截器是一种可以对请求和响应进行修改或监控的组件,它实现了Interceptor接口,该接口只有一个方法:intercept,它接收一个Chain对象作为参数,并返回一个Response对象作为结果。

Chain是一个接口,它提供了一个方法:proceed,用于调用链中的下一个拦截器,并维护当前拦截器的索引和列表。Chain对象负责执行intercept方法,并将自身作为参数传递给下一个拦截器继续处理。

7、OkHttp中的拦截器
OkHttp中有多种拦截器,它们可以对请求和响应进行修改或监控,例如重试、重定向、缓存、连接、桥接等。³

8、OkHttp拦截器执行流程大致如下:

  1. 首先,用户通过OkHttpClient发起一个网络请求,该请求会被封装成一个Call对象,并加入到任务队列中等待执行。⁴
  2. 然后,Call对象会被分配给一个异步线程来执行,该线程会创建一个Transmitter对象,用于管理请求的发送和取消。⁴
  3. 应用层拦截器】然后,会创建拦截器列表。将用户添加的应用层拦截器添加到列表中interceptors.addAll(client.interceptors())(通过OkHttpClient.addInterceptor方法添加)
  4. 重试和重定向拦截器】接着,将RetryAndFollowUpInterceptor对象作为第二个拦截器添加到拦截器列表中。该拦截器负责实现重试和重定向的功能。⁴
  5. 桥接拦截器】接着,将BridgeInterceptor对象,并将其作为第三个拦截器加入到拦截器列表中。该拦截器负责将用户构造的请求转换为向服务器发送的请求,将服务器返回的响应转换为对用户友好的响应。⁴
  6. 缓存拦截器】然后,会创建一个CacheInterceptor对象,并将其作为第四个拦截器加入到拦截器列表中。该拦截器负责读取缓存、更新缓存、处理缓存策略等。⁴
  7. 链接拦截器】接着,会创建一个ConnectInterceptor对象,并将其作为第五个拦截器加入到拦截器列表中。该拦截器负责建立与服务器的连接,并创建一个Exchange对象来管理连接的使用和释放。⁴
  8. 网络拦截器】然后,将用户添加的网络层拦截器添加到列表中interceptors.addAll(client.networkInterceptors())(通过OkHttpClient.addNetworkInterceptor方法添加)
  9. 请求服务拦截器】接着,创建一个CallServerInterceptor对象,并将其作为最后一个拦截器加入到拦截器列表中。该拦截器负责从服务器读取响应,并处理异常情况。⁴
  10. 将拦截器列表作为参数,构造出RealInterceptorChain
  11. response = chain.proceed() 开始责任链的调用,并且获取到响应
应用层拦截器

OkHttp应用层拦截器的使用方法有:

  1. 创建一个实现了Interceptor接口的类
    1. 重写intercept方法,该方法接收一个Chain参数,代表当前的拦截器链,
    2. 可以通过chain.request()获取请求对象
    3. 可以通过chain.proceed(request)获取响应对象,也可以修改请求或者响应对象。
  2. 使用OkHttpClient.Builder().addInterceptor(interceptor)方法添加自定义的拦截器,可以添加多个拦截器,它们会按照添加的顺序执行。
  3. 使用OkHttpClient.newCall(request)方法发起请求,请求会经过所有的应用层拦截器,然后到达网络层。

代码:请求+getResponseWithInterceptorChain

// 用户通过OkHttpClient发起一个网络请求
Request request = new Request.Builder()
    .url("https://www.example.com")
    .build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);

// Call对象被分配给一个异步线程来执行
call.enqueue(new Callback() {
    @Override
    public void onResponse(Call call, Response response) {
        // 处理响应结果
    }

    @Override
    public void onFailure(Call call, IOException e) {
        // 处理异常情况
    }
});

RealCall

  //依次执行拦截器链中的拦截器获取结果
  Response getResponseWithInterceptorChain() throws IOException {
    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());
    }
    //添加连接服务器拦截器,主要负责将我们的Http请求写进网络的IO流中
    interceptors.add(new CallServerInterceptor(forWebSocket));
 
    //构建拦截器链依次执行每一个拦截器
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值