vlambda博客
学习文章列表

Android 责任链设计模式学习应用实例

一、责任链模式介绍

责任链模式(Iterator Pattern),是行为型设计模式之一。生活中常见的锁链,就是由一个个圆角长方形的铁环串起来的结构。对于链式结构,每个节点都可以被拆开再连接,因此,链式结构也具有很好的灵活性。

将这样一种结构应用于编程领域,将每一个节点看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请求从链式的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止,我们将这样的一种模式称为责任链模式。
Android 中很多地方用到了这个设计模式,例如事件的传递,okhttp 中的拦截器等等!

二、责任链模式定义

使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链模式的使用场景

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。

  • 在请求处理者不明确的情况下向多个对象中的一个提交一个请求。

  • 需要动态指定一组对象处理请求。

三、责任链模式UML类图

Android 责任链设计模式学习应用实例

角色介绍:

  • 抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。

  • 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。

四、责任链模式实现案例

这个例子我觉得很贴切。我们在公司有各种原因需要报销费用,首先我们要找我们的上级领导去审批,报销额度如果在领导的权限范围内,那就审批通过,否则领导在找自己的上级去审批,以此类推。

1、抽象领导类

public abstract class Leader {
  /**
   * 上级领导处理者
   */

  protected Leader nextHandler;
  /**
   * 处理报账请求
   * @param money 能批复的报账额度 
   */

  public final void handleRequest(int money){
    System.out.println(getLeader());
    if(money <=limit()){
      handle(money);
    }else{
      System.out.println("报账额度不足,提交领导");
      if(null != nextHandler){
        nextHandler.handleRequest(money);
      }
    }
  }
  /**
   * 自身能批复的额度权限
   * @return 额度
   */

  public abstract int limit();
  /**
   * 处理报账行为
   * @param money 具体金额
   */

  public abstract void handle(int money);
  /**
   * 获取处理者
   * @return 处理者
   */

  public abstract String getLeader();
}

在这个抽象的领导类中只做了两件事,一是定义了两个抽象接口方法来确定一个领导者应有的行为和属性,二是声明了一个处理报账请求的方法来确定当前领导是否有能力处理报账请求,如果没有这个权限,则将该请求转发给上级领导处理。

2、各个领导类的实现类

组长(额度1000):

public class GroupLeader extends Leader{
  @Override
  public int limit() {
    return 1000;
  }
  @Override
  public void handle(int money) {
    System.out.println("组长批复报销"+ money +"元");
  }
  @Override
  public String getLeader() {
    return "当前是组长";
  }
}

主管(额度5000):

public class Director extends Leader{
  @Override
  public int limit() {
    return 5000;
  }
  @Override
  public void handle(int money) {
    System.out.println("主管批复报销"+ money +"元");
  }
  @Override
  public String getLeader() {
    return "当前是主管";
  }
}

经理(额度10000):

public class Manager extends Leader{
  @Override
  public int limit() {
    return 10000;
  }
  @Override
  public void handle(int money) {
    System.out.println("经理批复报销"+ money +"元");
  }
  @Override
  public String getLeader() {
    return "当前是经理";
  }
}

老板(额度…):

public class Boss extends Leader{
  @Override
  public int limit() {
    return Integer.MAX_VALUE;
  }
  @Override
  public void handle(int money) {
    System.out.println("老板批复报销"+ money +"元");
  }
  @Override
  public String getLeader() {
    return "当前是老板";
  }
}

3、发起申请

public class Client {
  public static void main(String[] args) {
    //构造各个领导对象
    GroupLeader groupLeader = new GroupLeader();
    Director director = new Director();
    Manager manager = new Manager();
    Boss boss = new Boss();
    //设置上级领导处理者对象
    groupLeader.nextHandler = director;
    director.nextHandler = manager;
    manager.nextHandler = boss;
    //发起报账申请
    groupLeader.handleRequest(8000);
  }
}

4、结果

当前是组长
报账额度不足,提交领导
当前是主管
报账额度不足,提交领导
当前是经理
经理批复报销8000

责任链模式非常灵活,请求的发起可以从责任链的任何一个节点开始,也可以改变内部的传递规则。比如主管不在,我们完全可以跨过主管直接从组长那里转到经理。

对于责任链中的一个处理者对象,有两个行为。一是处理请求,二是将请求传递到下一节点,不允许某个处理者对象在处理了请求后又将请求传送给上一个节点的情况。

对于一条责任链来说,一个请求最终只有两种情况。一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称为纯的责任链模式,后一种为不纯的责任链。实际中大多为不纯的责任链。

五、Android源码责任链模式

View事件的分发处理

ViewGroup事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体体现在View的onTouchEvent方法中返回值的设置,如果返回false,那么意味着当前的View不会是该次的责任人,将不会对其持有;如果返回true,此时View会持有该事件并不再向外传递。

Android view的树形结构:

Activity–>>PhoneWindow–>>decorView–>>ViewGroup>View

首先按下一个页面的按钮后,事件第一个传递的对象就是Activity,然后往下执行传递,在事件传递过程中我们通过dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法来处理事件的请求,

  • dispatchTouchEvent

    事件下发

    View和ViewGroup都有的方法

  • onInterceptTouchEvent

    拦截下发的事件,并交给自己OnTouchEvent处理处理

    ViewGroup才有的方法

  • onTouchEvent

    事件上报

    View和ViewGroup都有的方法

六、总结

对于责任链中的一个处理者对象,其只有两个行为,一是处理请求,二是将请求转送给下一个节点,不允许某个处理者对象在处理了请求后又将请求转送给上一级节点的情况。

优点

  1. 降低耦合度:客户端不需要知道请求由哪个处理者处理,而处理者也不需要知道处理者之间的传递关系,由系统灵活的组织和分配。
  2. 良好的扩展性:增加处理者的实现很简单,只需重写处理请求业务逻辑的方法。

缺点

  1. 请求会从链头发出,直到有处理者响应,在责任链比较长的时候会影响系统性能。
  2. 请求递归,调试排错比较麻烦。

对于一条责任链来说,一个请求最终只有两种情况,一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称该责任链为纯的责任链,对于后一种情况我们称为不纯的责任链,在实际应用中,我们所见到的责任链模式大多为不纯的责任链。