细细品读 Retrofit 的设计之美一

来源:互联网 发布:linux udp端口禁用 编辑:程序博客网 时间:2024/05/04 12:05

作者 | JerryloveEmily

地址 | http://www.jianshu.com/p/2ff63eb587cf

声明 | 本文是 JerryloveEmily 原创,已获授权发布,未经原作者允许请勿转载



前言

Retrofit 是这两年比较流行的网络通讯库,之所以流行自然有它的优点,首先是大厂 Square 公司开源之作,俗话说大厂出品,必须精品。
作为网络通讯框架,基本的组成部分就是三大块:1. 请求体部分。2. 响应体部分。3. 与UI层回调部分。


Retrofit的使用这里就不细说了,我们从构建Retrofit对象谈起。

首先:构建者Builder模式

整体看很明显有个构建者Builder模式,Builder模式在Android中是很常见的一种设计模式,它的优点很明显一般情况一个框架都是需要灵活自由的配置参数属性的,如果不用Builder模式,都改成setter、getter,那初始化一个Retrofit对象就显得复杂和臃肿了。而这里Builder模式加上链式调用方式,为Retrofit框架的参数配置增添了不少灵活和自由,而且代码可读性也增强了。


其实 Builder 模式的套路很简单,下面来个简单的伪代码Builder模式:



以上就是Builder模式的套路模板,外部Retrofit的对象的构建最终是在build()方法new出来返回。


Retrofit框架内部有好多地方都用到了Builder模式,也是为了方便自由配置参数的。


Builder模式在Android开发中最常见的就是AlertDialog.Builder,可以自由的配置对话框的标题、内容、内容设置来源、确认取消等按钮事件等等。有兴趣的可以去了解下AlertDialog的源码,基本也是上面模板的套路。


代理模式

构建好 Retrofit 对象后,大家都知道这个框架网络请求的通讯接口 api 都是 Interface 接口中声明的,框架本身为了与网络请求业务做解耦用了动态代理的方式,为业务通讯接口生成代理对象,当代理对象调用业务接口方法 api 的时候,动态代理类就能监测到并回调,这时候就可以做网络框架该有的功能:解析通讯业务接口,生成网络请求体便于供应给底层OkHttp 做具体的网络请求工作。其实就是框架本身没有办法直接使用业务接口,所以请了一个代理中介对象去间接的访问业务接口,来完成相关的业务功能。



来看看create方法是如何创建出ApiService接口的对象的。


通过Proxy.newProxyInstance方法动态创建了代理对象,也就是上文create方法返回的mApiService对象。是不是很懵逼,为什么Proxy.newProxyInstance方法就能创建出代理对象,而且又正好是ApiService.class这个接口对象呢,是怎么创建出来的?带着这些问题,我们来聊聊“代理模式”。


要搞清楚上面的这些问题,就得明白代理模式的套路,最重要就是区分清楚角色:
角色一:目标接口
角色二:目标对象
角色三:代理对象


这里先举个简单的例子,有个这样的场景:


Jerry是个程序员年纪大了眼看就要30岁了还是单身,家里人非常的着急,于是找到了隔壁老王(老王认识的妹纸比较多,为人热情)叫着帮忙介绍妹子给Jerry认识。


上面这个场景来区分下角色:
角色一:目标接口,大龄单身汪找妹子(要干的事情)
角色二:目标对象,单身程序员Jerry(需要找妹子的目标人物)
角色三:代理对象,皮条客隔壁老王(代表Jerry去找妹子)


这里创建三个文件:目标接口 IFindGirl、目标类Jerry、代理类ProxyLaoWan



使用的时候很简单:


这个例子中Jerry没有直接去找妹子“Tom”,而是通过了老王,这是一个典型的静态代理模式,Jerry把找妹子的事情委托代理给了老王,同样Jerry如果还有其它的事情,比如买最新的肾phone手机,可是国行的很贵,刚好老王要去香港,又委托老王买港版的iPhone X,于是就要IService目标接口中加入新的要干的事情buyPhone(),同样老王的类、Jerry类都需要实现相应的方法。如果Jerry不断的有新的事情要做,新的功能要扩展那需要修改的地方就比较多了不利于项目的扩展和团队开发。为此这样的需求就产生了动态代理模式。


先来看看套路模板:



Jerry如果还要委托老王给买手机,只要给目标接口加入buyPhone方法,然后Jerry实现这个方法,而代理者老王,不需要管都有什么具体的目标接口,通过Proxy.newProxyInstance创建的代理对象,就可以调用目标接口的方法。


介绍下Proxy.newProxyInstance方法:



第一个参数:目标对象的类加载器。因为这个代理对象是运行时才创建的,没有编译时候预先准备的字节码文件提供,所以需要一个类加载器来加载产生Proxy代理里的类类型,便于创建代理对象。
第二个参数:interfaces是目标接口数组
第三个参数:是代理对象当调用目标接口方法的时候,会先回调InvocationHandler接口的实现方法invoke。


到目前为止还是看不出来Proxy.newProxyInstance是怎么给我们创建代理对象的,下面分析下它的源码实现:


动态代理的源码实现


从上面代码中我们可以看出,最终的代理对象的创建是底层NDK来创建返回的,具体就不去看底层的实现了,大体了解到动态代理对象是通过这个构造方法来创建的。

经过上门对动态代理模式的一番学习和解释,现在回过头来看



create方法创建返回的正是ApiService接口的代理对象,每当代理对象调用目标接口里的方法时,动态代理对象就会回调InvocationHandler接口的invoke实现方法。


在Retrofit中,动态代理模式的角色划分:
角色一:目标接口(委托方法),ApiService接口方法
角色二:目标对象(委托方),ApiService.class
角色三:代理对象,create创建的mApiService对象。


至此就把 Retrofit 中,动态代理业务的网络通讯接口讲清楚了,好处就是非入侵的方式,把网络通讯api调用代理出来,然后在调用回调的 invoke方法里统一处理和准备网络框架需要构建的请求体,作为后续加入到请求队列任务池中进行具体的网络请求。动态代理模式也是 AOP 的一种实现方式,切片思想的一种。做过 Java EE 服务端开发的对于 Spring 的AOP 应该深有体会,动态代理与 Annotation 的结合真是完美,这一点在Retrofit的各种请求方式、参数、url 路径等等的注解就体现了。




文章有些长,这是第一篇,后面还会持续更新关于 Retrofit 的解读,不单单是让你懂的 Retrofit 的原理,还让你学会感受设计模式的美妙。感谢你的阅读。



与之相关

1 软件开发中的 10 条最佳指导原则

2 Android 面试 | 全站式导航

3 2017 | 我在 5 个月时间里分享了 98 篇文章



微信号:code-xiaosheng





公众号

「code小生」


原创粉丝点击