Android 开发中常用设计模式解读之-责任链(阻拦器)

作者 : 开心源码 本文共5359个字,预计阅读时间需要14分钟 发布时间: 2022-05-12 共250人阅读

模式定义与设计解读

设计模式晦涩的定义总是难懂,但同时这些定义又有着独特的涵义。本文想通过最直观的例子,把这些晦涩的定义反应在代码层面上。代码是设计模式最直观的表达,当你看不懂定义时,代码会说话。希望这篇解读可以帮助到你。估计阅读10分钟。

定义

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

注意一下加粗的关键字,解读会重新定义这些难懂的定义。

解读

在生活经常存在一种场景,完成一件事情,需要串行执行几个步骤。比方把大象装冰箱,需要三个步骤。

  1. 把冰箱门打开
  2. 把大象装冰箱
  3. 把冰箱门关上

现在把这件事情笼统成代码,并与上文中的定义对应。

  • 请求指把大象装冰箱这件事情,对应一个数据结构 RequestContext
/** * 请求上下文 */public class RequestContext {  public Elephant mElephant;//大象  public Refrigerator mRefrigerator;//冰箱  public RequestContext(Elephant elephant, Refrigerator refrigerator) {    mElephant = elephant;    mRefrigerator = refrigerator;  }  public static class Elephant{  }  public static class Refrigerator{  }}
  • 一条链比较好了解,但是比较难笼统。既然做这件事需要串行好几个步骤,链条上自然也是围绕请求开展,既需要有获取请求的方法RequestContext getContext(),也需要有执行请求的方法procceed(RequestContext context)。这个方法有开始执行的意思,也有请求串行传递后继续执行的意思。

proceed 英 [pr?’si?d]
vi. 开始;继续进行;发生;

/** * 请求链 */public interface Chain {  /**   * 获取请求实体   */  RequestContext getContext();  /**   * 开始或者继续执行请求。   */  void proceed(RequestContext context);}
  • 对象指1.2.3操作大象和冰箱的三个步骤,可以把每次步笼统成一个解决请求的对象,万物皆对象。现在我们已经把请求封装在了链条里,那对于每个操作步骤,都直接来解决链条上的请求就可。
/** * 解决者 */public interface Handler {  /**   * 解决链条上的请求   */  void handle(Chain chain);}
  • 发送者和接收者其实是指操作步骤的动作。每个操作步骤都会有以下流程
  1. 先接收请求(接收)
  2. 解决请求 (解决)
  3. 通知Chain,继续执行请求。(发送)

每个操作步骤只要要关注自己需要如何操作请求,而不需要关心操作完成后下个步骤是什么。只要要通知Chain,我执行完毕了,可以继续执行下一步了。从而避免了发送者和接收者之间的耦合关系。那么如何解耦呢,自然是链条来处理。链条上持有一系列操作步骤,存储成List<Handler>,并且记录当前执行到第几步int index,再结合之前定义的Chain接口,Chain实现类如下

/**  * 链实现类  */public class ProcessChain implements Chain {  public List<Handler> mProcessors;  public RequestContext mChainContext;  public int mIndex;  public ProcessChain(List<Handler> processors, int index, RequestContext chainContext) {    mProcessors = processors;    mIndex = index;    mChainContext = chainContext;  }  @Override  public RequestContext getContext() {    return mChainContext;  }  @Override  public void proceed(RequestContext processContext) {    if (mProcessors.size() > mIndex) {      //获取当前解决者      Handler processor = mProcessors.get(mIndex);      //升级index 与 Context      ProcessChain nextChain = new ProcessChain(mProcessors, mIndex + 1, processContext);      //解决者执行解决步骤      processor.handle(nextChain);    }  }}

proceed方法可能会觉得有些绕,其实道理很简单。着重了解一下nextChain就可,这里是重新构造了一个Chain,其实也可以了解为升级了一下Chain的数据,将index+1,以及升级RequestContext 。接下来讲到Processor的实现类,二者结合起来了解会更容易nextChain

  • Handler实现类。接收的概念好了解,就是接口方法handle(Chain chain)中的参数。那么什么是发送呢,我们回到上文nextChain,实际handle(Chain chain)方法接收的参数就是下个节点的Chain,我们只要要在handle()方法中解决完毕后,继续调用chain.proceed()方法,通知链条继续执行即可以了。请求就这样被发送出去了。
/** * 打开冰箱 */public class HandlerOpenRefrigerator implements Handler {  @Override  public void handle(Chain chain) {    RequestContext requestContext = chain.getContext();    //解决具体操作    if(!requestContext.mRefrigerator.isOpen()) {      requestContext.mRefrigerator.open();    }    //解决完毕 继续执行下个操作    chain.proceed(requestContext);  }}
  • 阻拦器 当我们执行到第二步时,需要装大象,假如这时候门没打开怎样办?任务执行不下去,我们可以选择中断链条,退出本次串行任务。这种链条上的任务传递和适当时机终止结合起来就是我们经常说的阻拦器阻拦器就是基于责任链模式,每个节点有自己的职责,同时可以选择能否把任务传递给下一个环节
/** * 移动大象 */public class MoveElephantHandler implements Handler {  @Override  public void handle(Chain chain){    RequestContext requestContext = chain.getContext();    //解决具体操作    if(requestContext.mRefrigerator.isOpen()) {      requestContext.mElephant.move();      //解决完毕 继续执行下个操作      chain.proceed(requestContext);    }else{      //发生异常 中断链条      chain.abort();    }  }}

推荐阅读:阿里腾讯Android开发十年,到中年危机就只剩下这套移动架构体系了!

讲到这里再回头读一下最开始定义的那句话。你会有不一样的了解。假如没有,自己敲一遍代码再试试。

  • 运行 依次构造请求,责任链,而后开始任务。
public class MyClass {  public static void main(String[] args) {    //构造请求    RequestContext requestContext = new RequestContext(new RequestContext.Elephant(),new RequestContext.Refrigerator());    //构造解决步骤    List<Handler> list = new ArrayList<>();    //你也可以不加打开冰箱试试结果    list.add(new OpenRefrigeratorHandler());    list.add(new MoveElephantHandler());    list.add(new CloseRefrigeratorHandler());    //执行任务    ProcessChain processChain = new ProcessChain(list,0,requestContext);    processChain.proceed(requestContext);  }}

Demo地址

思想了解与实践运用

了解

责任链重点是在解耦,如何将一个任务的不同步骤之间没有耦合关系,每个步骤专注负责自身,而不需要关心其余步骤,以及其余步骤的变化,这些变化可以交给更高层次来控制,而不是在任务节点上控制。比方上述例子中,假如装大象上线后发现很容易失败,需要先把大象切开(一个残忍的举例),那么只要要在控制层增加list.add(new CutElephantHandler)就可。这种修改对于既有的代码侵略性极低,由于步骤之间解耦很彻底,并且这种可插拔式的代码,组合性极强。使得代码的扩展性和可维护性极高。

运用

  • 框架中的运用OkHttp中有使用Interceptor就是一个经典的例子。来看看源码中的定义
/** * Observes, modifies, and potentially short-circuits requests going out and the corresponding * responses coming back in. Typically interceptors add, remove, or transform headers on the request * or response. */public interface Interceptor {  Response intercept(Chain chain) throws IOException;  interface Chain {    Request request();    Response proceed(Request request) throws IOException;  }}

是不是很熟习。Okhttp中阻拦器就是责任链模式运用。我们在进行应用开发的时候都会在请求中添加少量通用信息,比方在 header 中添加客户的token信息等等以及在请求的过程中修改请求的 requestresponse。那么我们即可以定义不同的Interceptor来解决。这些阻拦器之间没有任何关联,只关注自己解决过程。现在回头再去看看少量OKhttp的源码解读应该就很容易了解其精髓了。

  • 实际开发中的运用:除了在少量既有的框架中使用,我们在Andorid实际开发场景中如何运用呢。再举个在项目中使用过的场景。我们的App,在HomeActivity启动后,会依次做几件事情
  1. 检测更新,出现弹窗1
  2. 弹窗1关闭后,出现引导Window
  3. 引导图关闭后,出现选择语言弹窗。

假如需要是一步一步加上来的。比方第一个版本,我们只有检测更新。代码肯定很直接,onCreate()方法里showUpgradeDialog()。当来了第二个需求,代码直接写就会变成这样。在更新弹窗的Dialog onDismissListenershowGuideWindow(),假如第一步未检测到更新,还需要判断if(!needUpgrade)直接showGuideWindow()。代码写到这里,这两个步骤已经耦合在一起了。引导window能否出现,跟检测弹窗几乎绑定在一起。假如有一天产品脑洞大开,我们先出引导再更新吧!想想你的代码会怎样改。
window的 onDismissListener 里showUpgradeDialog()?假如使用责任链模式呢?在控制层换一下顺序就好了。

  • 大家可以尝试找一下项目里相似的需求,少量任务需要串行执行的地方,假如耦合严重,试着重构一下。

总结

设计模式在开发实践中,对代码的可读,可扩展,可维护性起到重要作用。在面试中,经常会和面试者聊聊设计模式,大部分面试者都停留在设计概念本身,假如能阐述更多对设计模式的了解与在实践中的运用,相信会对你的面试有帮助。本文也给大家举一个设计模式学习的例子,从模式学习,思想了解到实践运用。回头再读一下本文重点:

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

Android设计模式等

关于Android进阶的一律学习内容,我们这边都有系统的知识体系以及进阶视频资料,有需要的朋友可以加群免费领取安卓进阶视频教程,源码,面试资料,群内有大牛一起交流探讨技术;点击链接加入群聊【腾讯@Android高级架构】
(包括自己设置控件、NDK、架构设计、混合式开发工程师(React native,Weex)、性能优化、完整商业项目开发等)

Android高级进阶视频

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android 开发中常用设计模式解读之-责任链(阻拦器)

发表回复