设计模式-职责链/责任链模式(Chain of Responsibility)分析理解和在Android的应用

原创 2016年06月01日 01:17:07

介绍

我一直感觉Android源码不能只简单的看,结合设计模式的思想再去看源码会有更深的理解。但是源码中应用某个设计模式,会根据实际情况会有一些差异。所以需要先透彻地理解设计模式。熟悉设计模式的应用场景就可以在Android源码的场景中找到相应的实现,熟悉设计模式就能够透过浩瀚的源码看到本质。
今天突然想到有关View点击事件的分发,感觉它的设计需求就很符合职责链模式(Chain of Responsibility)的应用场景。《Android源码设计模式解析与实战》中也说到了这点。所以本篇先重点介绍职责链模式。
如果已经理解该模式可以直接看下篇:
Android开发-分析ViewGroup、View的事件分发机制、结合职责链模式

职责链模式介绍

定义

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

应用场景

想象这样的一个需求场景:在公司里面申请活动费用,申请人填写表格,交给上级审批,如果活动费用数额在上级的处理范围就处理,然后返回通过请求,否则上级再交给他的上级,处理逻辑同样。最后肯定有一个人处理。

针对上面的场景,就是职责链模式的最典型应用场景。

UML图

职责链模式UML图

  • Handler:定义职责接口,通常在内部定义处理请求的方法,可以在这里实现后继链。
  • ConcreteHandler:实际的职责类,在这里个类里面,实现在它职责范围内的请求处理,如果不处理,就继续转发请求给后继者。
  • Client:客户端,组装职责链,向链上的具体对象提交请求。

图中最关键的点就是:那条从Handler出发又指向自己的线,它就是实现链式调用的关键。

代码

先上图是为了能够先看清职责链模式的大概框架。现在用实际代码和运行结果展示该模式的实现思想。

Handler抽象类

Handler抽象类作为职责接口,是所有职责对象的父类。

/**
 * Created by LiCola on  2016/05/31  23:16
 */

public abstract class Handler {
    /**
     * 内部持有后继的职责对象
     */
    protected Handler successor;

    /**
     * 注入后继职责对象
     * @param successor
     */
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    /**
     * 抽象父类统一请求处理方法
     * 可以在方法中传值 作为判断条件 也可以不传值利用其它外部条件
     */
    public abstract void handlerRequest(int cost);
}

具体的职责实现对象

为了简洁起见,只实现两个具体的职责对象,在方法内部都提供结果打印显示处理流程。

职责对象1

/**
 * Created by LiCola on  2016/05/31  23:19
 */

public class ConcreteHandler1 extends Handler {

    @Override
    public void handlerRequest(int cost) {
         /*
          根据某个条件判断是否是自己的处理职责范围
          一般是传入的值 或者外部数据
         */

        if (cost<1000){
            //如果是自己的职责范围 就在内部处理
            System.out.println(this.getClass().getSimpleName()+" handler event");
        }else {
            //如果不在自己的职责范围 就判断是否有后继者
            if (this.successor!=null){
                //存在后继者 讲请求传递
                System.out.println(this.getClass().getSimpleName()+" post handler");
                this.successor.handlerRequest(cost);
            }
        }
    }
}

职责对象2

/**
 * Created by LiCola on  2016/05/31  23:19
 */

public class ConcreteHandler2 extends Handler {

    @Override
    public void handlerRequest(int cost) {
        //简化流程 该对象一定能处理事件 不再下发
        System.out.println(this.getClass().getSimpleName()+" handler event");
    }
}

Client客户端

在这里客户端不是简单的调用,它还需要组装职责链,并发起请求

/**
 * Created by LiCola on  2016/05/31  23:27
 */

public class Client {

    public static void main(String[] args){
        //客户端需要自己组装职责链
        //构造职责对象
        Handler handler1=new ConcreteHandler1();
        Handler handler2=new ConcreteHandler2();
        //组装链
        handler1.setSuccessor(handler2);

        //发起请求
        handler1.handlerRequest(2000);

    }
}

分析

运行上面的代码,先看打印出来的结果:
打印结果

说明:
因为发出的请求不在ConcreteHandler1的处理范围,它将事件下发了,而ConcreteHandler2具有最高的权限范围,一定能处理请求。

上面的代码只是最简单的实现,只拼接了两个职责对象,根据实际情况可以有很多的职责对象。

再看一下职责链的调用过程加深印象:

Created with Raphaël 2.1.0客户端客户端职责对象1职责对象1职责对象2职责对象2发出请求不在职责范围,事件下发发出请求能够处理回应事件回应请求

模式讲解

看完上面的代码,相信你就能够理解这句话了:

客户端发出一个请求,链上的对象都有机会来处理这一请求,而客户端不需要知道谁是具体的处理对象。这样就实现了请求者和接受者之间的解耦,并且在客户端可以实现动态的组合职责链。

如果对上面的代码修改成:每个请求都不拦截,而是一步步的往下传,每一步都会处理请求对象,就可以变形成处理请求功能链。

这里提一个概念

隐式接受者:对于请求者而言,它并不知道最终的接受者是谁,但是一般情况下总会有一个对象来处理,因此称为隐式接受者

职责链的构造

刚才的代码只是示例,在客户端只简单的拼接了链。实际使用中,职责链的构造是非常重要的点。那如果构造职责链?

按照实现的角度来分:

  • 客户端组装职责链,在使用时动态的组合链,称为外部链,我们上面的代码就是实现了外部链。
  • Handler中实现链组合,可以称为内部链
  • 还可以在各个职责对象中,由对象自行决定后续处理的对象。这种方式要求每个职责对象处理进行任务处理外,还需要了解整个业务流程。

按照构造链的数据来源分,也就是决定了按照什么顺序呢来组合链的数据可以分为:

  • 在程序中动态组合
  • 通过外部,比如数据库来获取组合数据,这属于数据库驱动方式
  • 通过流程配置文件

如果是从外部获取数据来构建链,那么在程序运行时,会读取这些数据,然后根据数据的要求来获取相应的对象组合起来。

作为一个Android开发者,看到这里是不是感觉外部数据、配置文件、隐式接受者。会不会是App项目中的manifest文件中每个组件的 ,和我们平常的隐式启动Activity
我也只是猜想,没有经过具体的验证证明。附上Intent 和 Intent 过滤器,大家自己去看。

职责链模式的思考

说了这么多,下面总结一下职责链模式的优缺点

优点

  • 请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。
  • 动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。

职责链模式的最主要功能就是:动态组合,请求者和接受者解耦

缺点

  • 产生很多细粒度的对象:因为功能处理都分散到了单独的职责对象中,每个对象功能单一,要把整个流程处理完,需要很多的职责对象,会产生大量的细粒度职责对象。
  • 不一定能处理:每个职责对象都只负责自己的部分,这样就可以出现某个请求,即使把整个链走完,都没有职责对象处理它。这就需要提供默认处理,并且注意构造链的有效性

Android隐式Intent的隐患

说到职责链模式的缺点,突然想到Android开发中隐式Intent的隐患。
如果我们在代码中,想通过隐式启动处理某个用户请求,比如这样的代码

 Uri uri = Uri.parse(link);
 Intent intent= new Intent(Intent.ACTION_VIEW, uri);
  startActivity(intent);

可能的结果:当没有任何应用处理发送到 startActivity() 的隐式 Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。

所以要验证 Activity 是否会接收 Intent,请对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()。如果结果为空,则不应使用该 Intent。
对应的代码是这样的

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

应用场景

  1. 如果有多个对象可以处理同一个请求,但是具体由哪个对象处理是由运行时刻动态决定的,这种对象就可以使用职责链模式,把处理请求的对象实现成职责对象,然后构造链,当请求在这个链中传递的时候,会根据运行状态判断。
  2. 当不明确接受者的情况下。
  3. 当想要动态指定处理一个请求的对象集合

只所以把第一项说得这么细,就是因为它刚好就是我们Android开发中View的事件分发处理。手在屏幕上点击产生事件,每个View都是职责对象都可以处理事件。具体内容我会在下一篇博客详细分析。
下篇点这里: Android开发-分析ViewGroup、View的事件分发机制、结合职责链模式

总结

  1. 本文首先提出职责链模式概念,并用UML图和模板代码说明模式
  2. 模式讲解指出关键点
  3. 思考说明职责链模式的优缺点,引出Android隐式Intent的隐患并提出解决方案。最后指出应用场景。
版权声明:本文为博主原创文章,未经博主允许不得转载。

责任链模式的应用实例

责任链 实例 apache
  • oooooooooooooaaa
  • oooooooooooooaaa
  • 2010年10月23日 22:51
  • 7070

设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为

设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述        你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我...
  • hguisu
  • hguisu
  • 2012年05月08日 18:35
  • 37025

python的简单实际应用(一)

python的简单实际应用(一) 初步需求:将一整个文件夹各个子目录中所有目标文件的所有对应元素的相同属性名称的不同字段全部取出写到excel表格以供下一步使用。 整体思路:(1)递归出所有目标...
  • java_thinkinger
  • java_thinkinger
  • 2015年11月02日 17:16
  • 1077

MyBatis简单应用

MyBatis的前身就是iBatis,iBatis本是apache的一个开源项目,2010年这个项目由apahce sofeware foundation 迁移到了google code,并且改名为M...
  • a468903507
  • a468903507
  • 2015年03月23日 23:53
  • 723

在首席架构师手里,应用架构如此设计

转载自:http://geek.csdn.net/news/detail/73332 无架构,不系统,架构是大型系统的关键。从形上看,架构是系统的骨架,支撑和链接各个部分;从神上看,架构是系统的...
  • boonya
  • boonya
  • 2016年05月11日 17:26
  • 5346

信息论的简单应用

转载地址:http://blog.sciencenet.cn/blog-677221-669159.html 我在帖子“大将军数学题2-答案”中,出了一道有关用老鼠检测毒药瓶的附加题:   有1...
  • zhongjishao
  • zhongjishao
  • 2013年04月10日 15:31
  • 1305

算法9-6:最大流的应用

最大流算法在现实生活中有着广泛的应用,从数据挖掘到图像处理,都有应用。现实生活中很多事物看起来是不相干的,而实际上只要通过数学建模,其实很多问题本质上都是一样的。 这里举的一些例子很...
  • caipeichao2
  • caipeichao2
  • 2014年06月27日 20:08
  • 1584

谈谈FFT到底有何用(吴臻志)--很宽泛的介绍FFT应用

谈谈FFT到底有何用 谨以此献给一直在致力于FFT算法芯片设计的同行们   FFT(快速傅里叶变换)是数字信号处理的超级经典算法,学过DSP或者芯片设计的人大多知道这个算法。但是,大家是否想过,...
  • w15778225
  • w15778225
  • 2014年05月03日 17:01
  • 3674

TensorFlow最新应用&资源集锦

TensorFlow最新应用&资源集锦
  • x_r_su
  • x_r_su
  • 2016年11月05日 11:25
  • 3542

Android 将自己的应用改为系统应用

所谓系统程序就是system/app目录中的程序,普通应用转换成系统程序后有稳定、减少内存(DATA)空间占用、恢复出厂设置后不会消失、修改系统时间、调用隐藏方法、系统关机重启、静默安装升级卸载应用等...
  • xx326664162
  • xx326664162
  • 2016年11月30日 16:19
  • 13012
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式-职责链/责任链模式(Chain of Responsibility)分析理解和在Android的应用
举报原因:
原因补充:

(最多只允许输入30个字)