设计模式之责任链模式

定义: 责任链模式,多个对象处理请求时,为了避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链。并沿着这条链传递该请求,直到有对象处理它为止。责任链模式的重点就在一个“链”字上,沿着这个条链处理这个请求,返回结果。观察者模式是一种行为型设计模式。

模型角色:

  • 抽象处理者角色:抽象处理逻辑,提供抽象处理函数和持有下一个处理者引用;
  • 具体处理者:具体的处理请求逻辑。接到请求后可以选择处理掉请求,或者将请求传递给下一个处理者。

责任链设计模式在我印象中最深的就是OkHttp中拦截链的设计。下面是添加拦截器的方法。

  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());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

Interceptor就是抽象处理者

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;
  interface Chain {
    Request request();
    Response proceed(Request request) throws IOException;
    @Nullable Connection connection();
  }
}

具体处理者1:

public final class BridgeInterceptor implements Interceptor {
  @Override public Response intercept(Chain chain) throws IOException {
    // 。。。省略部分代码逻辑
    Response networkResponse = chain.proceed(requestBuilder.build()); // 传递给下一个处理者
    // 。。。省略部分代码逻辑
    return responseBuilder.build();
  } 

具体处理者2:

public final class CacheInterceptor implements Interceptor {
 @Override public Response intercept(Chain chain) throws IOException {
 // 。。。省略部分代码逻辑
    Response networkResponse = null;
    try {
      networkResponse = chain.proceed(networkRequest);
    } finally {
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
  // 。。。省略部分代码逻辑 
 } 
} 

上面只列举了2个具体处理者,此外还有ConnectInterceptor、CallServerInterceptor等等以及自定义的拦截器。它们都处理一部分自己的逻辑,然后传递给下一个处理者。可能光看这几行代码看不出来哪里像责任链了。主要是OkHttp在处理方式上变化了一下,每个具体处理者都将传递给下个处理者的逻辑交给了一个类(RealInterceptorChain)去处理,只是相同的类,而不是同一个对象。每个具体处理者类中传递给下一个处理者的方法chain.proceed()实际都是调用 RealInterceptorChain#proceed():

public final class RealInterceptorChain implements Interceptor.Chain {

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
      //。。省略代码
      
      RealInterceptorChain next = new RealInterceptorChain( 
      interceptors, streamAllocation, httpCodec, connection, index + 1, request);
      Interceptor interceptor = interceptors.get(index); // 获取下一个处理者
      Response response = interceptor.intercept(next); // 下一个处理者的处理逻辑
      
      // 。。省略代码
  }
}

以上是OkHttp中的一个例子,想更加详细了解可以去翻阅它的源码。下面再用个请假流程简单的例子模拟这种设计模式。假定员工请假3天内只需要组长级别同意即可;大于3天需要部门经理级别同意;大于7天需要老板亲自同意。整个审批流程链大概是:
员工 -> 组长 -> 经理 -> 老板。下面用代码实现:
首先是声明抽象处理者,定义出抽象审批方法,提供设置下一个处理者的方法:

public abstract class ApprovalHandler {

    private ApprovalHandler handler; // 下一个处理者引用
    
    public abstract void approval(int day);

    protected void setHandler(ApprovalHandler handler) {
        this.handler = handler;
    }
    public void next(int day) {
        if (handler == null) {
            Log.d("TAG", "审批结束");
        } else {
            handler.approval(day);
        }
    }
}

具体处理者:

// 组长级别
public class AHandler extends ApprovalHandler {

    @Override
    public void approval(int day) {
        Log.d("TAG", "组长:同意");
        if (day < 3) {
            Log.d("TAG", "审批结束,请假" + day + "天");
        } else {
            next(day);
        }
    }
}

// 经理级别
public class BHandler extends ApprovalHandler {

    @Override
    public void approval(int day) {
        if (day <= 7) {
            Log.d("TAG", "经理:同意");
            Log.d("TAG", "审批结束,请假" + day + "天");
        } else {
            next(day);
        }
    }
}

// 最高级别
public class CHandler extends ApprovalHandler {

    @Override
    public void approval(int day) {
        Log.d("TAG", "老板:同意");
        Log.d("TAG", "审批结束,请假" + day + "天");
    }
}

使用:

AHandler a = new AHandler();
BHandler b = new BHandler();
CHandler c = new CHandler();
a.setHandler(b);
b.setHandler(c);
a.approval(1);
// a.approval(10);

输出结果:

组长:同意
审批结束,同意请假1天

组长:同意
经理:同意
老板:同意
审批结束,同意请假10天

应用场景:

  • 一个请求需要一系列的处理工作
  • 业务流的处理
  • 对系统进行补充扩展

优点:

  • 提高系统的灵活性;
  • 将请求和处理者分隔开,降低耦合度,请求不知道是哪个处理者处理的,处理者不用知道请求的全貌;

缺点:

  • 降低程序性能,需要从链头处理到链尾,整个链条很长的时候,性能大幅度下降。
  • 调试困难,请求与处理者分隔开,无法直接命中是哪一个处理者完成的请求。

小结
责任链一般用于处理类似流程节点之类的业务场景中。从它的命名上就可以看出一点端倪,一是责任分离,大伙儿各司其职;二是"链",按照执行顺序,依次处理。责任链上的各个角色都有机会处理请求,却不一定都会去处理请求,甚至都不处理请求(不属于责任范围内)。此外,要注意把控责任链中“链”的长度,避免影响整体性能。责任链(包括其他设计模式)还有很多的变种写法。就比如前面例子1(okHttp)和例子2写法上就有一些差距。Ok中的例子反而更像是一条“链”,例子2中的“链”流程形态体现更加明显。无论哪种写法,只要符合责任链的核心思想(责任分工,形成了"链")它都是责任链设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值