Retrofit2.3 设计模式分析

前言

最近学校的设计模式课程设计要求我们选一个框架进行设计模式的分析,结果老师给的题目都是跟Android毫无瓜葛的。这时候我想起了Retrofit,毕竟有一段时间曾经了解过,据说是设计模式的教科书。所以秉着作死的心态向老师自定义了题目(真™刺激呀),于是乎在一顿折腾后坎坷的看出大致的模式。这篇文章是一个学生党对框架设计模式的分析,可能有错误的地方,希望能得到大家的指导。

关于Retrofit

Retrofit是一个好东西,出自square公司之手,说到square公司自然不得不提一个大神,那就是jack wharton,很多现在流行的轮子都是他参与造的,比如这次的Retrofit啦,Rxjava啦,黄油刀啦,OkHttp啦等等。这里关于Retrofit的介绍就详细讲了,简书里有很多文章,大家可以搜搜。

Retrofit的基本使用


基本使用方法


使用注解定义一个接口

笔者用的是Kotlin语言,短短主题五行代码就可以简单的完成一次网络请求。与OkHttp相比呢也不用自己来写请求体和回应体的解析。或许这就是Retrofit受欢迎的原因之一吧。

  使用步骤描述:

1.先定义一个接口,使用@Get,@Path等注解定义,如上图。

2.创建一个Retrofit对象,使用其内部Builder类来进行对Retrofit对象的配置

3.创建一个Call(请求体),使用Retrofit的create方法传入定义好的接口

4.调用已创建Call的方法(接口内的方法),传入用户想要的参数

5.执行Call,返回一个回应体

6.对回应体进行一系列用户需要的操作

框架设计模式分析

1.分析框架的初步运行流程

Retrofit进行配置的流程


创建一个Call的流程

总结:Retofit类负责配置,其中会涉及到一些其他的类,如工厂什么的,但是最后Call的返回逻辑在ServiceMethod类中,ServiceMethod是一个很关键的类,涉及到了具体运行原理和调用,这里我们只做设计模式分析,就不深入啦。

2.深入分析


我们一步一步来,最后面会放上类图,咱们先不急。

第一步配置

第一步:配置Retrofit

从名字我们就可以看出,毫无疑问配置这一部用了个构造者模式呀(Builder),学生党我暗自偷笑。是不是不用看啦??不急不急,我们还是进去看一看。

Retrofit类的内部属性和部分方法

可以看到Retrofit类中包含了一个Builder类,点进去一看,是一个静态类(这里就不放图了),再看看上图中若干个addXXX方法和一些其他方法均是返回Builder自身的,还有一个build()方法返回一个Retrofit的,这一罗列,哎呀妈呀果真是构造者方法,错不了错不了。

知道这里是使用了构造方法后,那有什么用呀?因为网络请求要配置各种参数,而有些参数是不必要的,如果不使用构造者模式,那Retrofit就必须得写一大串参数类型不同的构造器,用于对参数传入,那代码就非常的不雅,可读性也很差,所以就用了个Builder啦。

等等!就这么完了吗?但是你仔细看一下参数,addXXXFactory?里面竟然维护了一个叫XXFactory的列表?这难道是...抽象工厂??工厂方法??(学生党暗自偷笑,这作业稳了)我们先点进去一探究竟


我们点进CallAdapter.Factory


惊了,一个接口里面有个抽象类,一个抽象方法
看一下这个抽象类的实现,有4个,其中有2个一样的是因为版本不同的问题


嗯。。没什么特别,这里就用到了一个简单的单例..我们看下一个


这个工厂有一个内部类ExecutorCallBackCall,还实现了Call接口

经过一顿分析,可以非常确定这是一个抽象工厂和工厂方法的设计模式。CallAdapter.Factory为抽象工厂,CallAdapter为工厂的产品接口,而上图中的ExecutorCallAdapterFactory和DefaultCallAdapterFactory为他的实现类,其中ExecutorCallAdapterFactory中的内部类ExecutorCallBackCall为该工厂的产品,实现了Call接口。

等等!!你说ExecutorCallBackCall是工厂的产品?但无论是从名字上来看还是从接口上来看都不应该啊?因为他实现了Call接口,但没有实现产品应该实现的CallAdapter接口啊?

的确如此,但是。CallAdapter这名字不觉的很熟悉吗?没错Adapter,其实这里还用了一个适配模式,而这整一个工厂最终目的是返回一个适配器,基于某种兼容目的的适配器。

匿名实现了CallAdapter接口,其中里面就返回ExecutorCallbackCall

也就是说,产品其实是他匿名实现的CallAdapter,只是里面返回了一个ExecutorCallbackCall,这里利用创建工厂实现时传进来的一个实现了Java Executor接口的类,来进行对参数call的一个适配。

这里你会很好奇为什么ExecutorCallbackCall传进一个实现了Java Executor接口的类和一个call做为参数。


ExecutorCallbackCall实现的Call接口结构
ExecutorCallbackCall 内部的结构

经过一番查看,先看看Call接口,ExecutorCallbackCall实现的Call接口和在适配方法中传进来的call参数实现的接口是一毛一样的!!而从类的结构来看,看属性delegate的调用。是的,其实该类的实现实际是交给(委托)给传进来的call参数(delegate属性)实现的,然后只是在使用另一个传进来的参数(callbackExecutor)环境中运行【看红线部分】。

也就是说。这个类是包装用的,实现的功能都是委托给call的。装饰器模式,不知道为何脑内浮现出这几个大字...

到此。我们连同装饰器,适配器整个抽象工厂,工厂方法分析完毕。这一层套一层,环环相扣,这让人颤栗啊,这™设计的太可怕的。多种设计模式的运用巧而不显冗杂,岂是我等能做到的!

还有一点要提,我们上课的时候喜欢把产品接口和抽象方法分开两个文件来写,但是这里是将抽象工厂写在了接口中。这很巧妙,因为这样使用的时候就非常明显【接口.抽象工厂】,一看就知道这工厂的产品和抽象。而且合在一起写也不用为命令感到烦恼。

总结一下:


类图结构

我们从配置Retrofit为出发点,分析出了抽象工厂,工厂方法,单例,适配器,装饰器五种模式。可能就要问了,在哪里开始初始化了这个工厂?有两个地方

第一:通过Retofit中Builder的addCallAdapterFactory方法


通过Retofit中Builder的addCallAdapterFactory方法

第二:在我们调出Builder时,在无参构造器中,通过调用Platform.get()来初始化


Builder的无参构造器
Platform类内部结构

What??Platform啥玩意?不用担心,源代码作者命名非常好,看名字大概就知道,是平台嘛,平台类是干嘛?

可以看出里面有两个内部静态类Java8和Android,还有两个defaultCallXXX的方法。到这里我们就可以结合适配器工厂和这里两个内部类的类名揣测出适配器是为了适配不同平台下的运行环境。Android有主线程(UI线程)而Java8则没有

Android
Java8

这里框架就默认实现了两个平台。Platform类是可继承的,如果没有我们的需求就可以继承该类并实现自己的平台。

说要这里第一步配置就说完了,但是返回文中刚开始的地方,你会看到一个叫converterFactories的列表,这是一个converter工厂的列表,也是一个抽象工厂,这里就不详细说了,下面只给出类图,仅供大家参考


画的好丑。用于解析网络返回体结果。如Gson

第二步:使用create方法传入接口,返回call


使用步骤的第二步

老规矩咯,点进去看看..

™™™

哎呀woc这什么东西。学生党看不懂,但是我们从Proxy这个名字可以看出,或许是个代理模式。经过资料查询后发现,这里是实现了Java中自带的动态代理。何为动态代理?就是在创建一个实例前,你或许要对这个实例动点手脚,而我们又不能在创建实例的是时候决定要动点什么手脚,所以先创建一个代理对象给你用着先,等你动完该动的手脚,才开始真正创建实例。也就是说,这里我们调用create方法本来是要返回一个call对象的,但是!我们要在传入需要的参数后才能真正创建call对象,也就是说在文中开始的第三步后才真正创建了一个call。

如上图,create只是创建了个代理,当调用了代理内的方法后(接口放射后的方法)才开始创建真正的实例

这里笔者就不探究动态代理如何实现的了(因为我也不会呀..)我们继续往下看,这动态代理内的代码

首先是调用了自身的loadServiceMethod方法,加载(获得)了一个ServiceMethod类,然后通过其创建了一个OkHttpCall实例,最后调用了serviceMethod实例中的一个callAdapter对象中的adapt方法,最终返回了一个call。为这个adapt方法就是之前分析中的工厂方法产品类的方法。

查看一下loadServiceMethod的代码


非常简单..

看来Retrofit内部保存了一个ServiceMethod的map(key是从接口中反射出来的方法),没找到的话就通过ServiceMethod的Builder构造一个(又是一个构造者方法),然后存进map中。而ServiceMethod中就会创建callAdapter,这其中又会跳回Retrofit中,从其维护的callAdapter工厂列表中查找..挺复杂的,就不说啦,毕竟原则是设计模式分析嘛。

再看看用serviceMethod构造的OkHttpCall


其实现了call接口,就是之前在分析适配器讲到的call接口一样的。里面包含了一个另一个call接口:rawCall,这个rawCall与上面的call不同,因为他是来自okhttp3的。也就是这里的OkHttpCall其实就是包装了okhttp3中的call,功能的调用都委托给他..又一个装饰器。

总结

到这里,Retrofit中用到的设计模式我能发现到的,基本分析完了,里面运用了抽象工厂,工厂方法,单例,装饰器,适配器,动态代理。光是配置这一步就用了前六种设计模式..太可怕了..

希望你们能看懂...虚心接受指导和更正..

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容