通过okhttp拦截器demo加深对责任链模式的理解
责任链模式的思想
将事件或者数据传递到第一个处理者身上,每一个处理者都持有下一个处理者的引用,从第一个处理者开始决定:
-
拦截数据自己处理,不传递给后面的处理者
-
不拦截数据,加工数据后传递给下一个处理者
-
。。。重复步骤1,2
-
如果都没人拦截,数据一直返回到最初的地方(通过return的方式,后面通过例子演示)
例子
建议把代码复制到编辑器里点击跳转走一遍,更容易理解
像okhttp那样,通过建造者模式添加所写的拦截器
fun main() {
val data = "hello"
val jkHttpClient = JkHttpClient.Builder()
.baseUrl(data)
.addInterceptor(LoggerInterceptor())//添加拦截器的先后顺序会影响结果
.addInterceptor(EncodeInterceptor())
.build()
jkHttpClient.enqueue {
println("用户收到的json数据: ${it}")
}
}
class JkHttpClient(
private val url: String,
private val interceptorList: MutableList<Interceptor>
) {
class Builder {
private var interceptorList = mutableListOf<Interceptor>()
private var url = ""
fun baseUrl(url: String): Builder {
this.url = url
return this
}
fun addInterceptor(interceptor: Interceptor): Builder {
interceptorList.add(interceptor)
return this
}
fun build(): JkHttpClient {
return JkHttpClient(url, interceptorList)
}
}
fun enqueue(callback: (String) -> Unit) {
val realChainProcessor = RealChainProcessor(0, interceptorList)
//当前第二个参数传的null没任何意义
val response = realChainProcessor.proceed(url, null)
callback.invoke(response)
}
}
这里通过enqueue方式去发起请求,具体的操作交给了RealChainProcessor的proceed方法,并将最终结果回调出去
定义所需要的功能接口
interface Interceptor {
//实现类做处理的方法
fun intercept(url: String, chain: Chain): String
interface Chain {
//发起请求
fun request(url: String, chain: Chain): String
//拦截器处理数据
fun proceed(url: String, chain: Chain?): String
//返回结果
fun response(url: String): String
}
}
这里定义接口方法的时候,由于不是完全按照okhttp的写法,只是大概模拟个过程,一下子想不到方法配什么参数,是否要返回值,返回值是什么,都是编写边想边改的
class RealChainProcessor(var index: Int, val interceptorList: MutableList<Interceptor>) : Interceptor.Chain {
override fun request(url: String, chain: Interceptor.Chain): String {
//发起网络请求
println("假装发起网络请求")
return chain.response(url)
}
override fun proceed(url: String, chain: Interceptor.Chain?): String {
//当index大于等于拦截器的数量的时候,说明拦截器都已经执行完了,这时候需要去发起网络请求了
if (index >= interceptorList.size) {
return chain!!.request(url, chain)
} else {
val interceptor = interceptorList[index]
//拿到下一个拦截器的处理对象
val nextProcessor = RealChainProcessor(index + 1, interceptorList)
//遍历拦截器
index ++
//当前的拦截器去执行具体的处理操作,并将下一个处理对象提前传入,
//当处理操作结束后,通过处理对象可以进行自己的处理操作
return interceptor.intercept(url, nextProcessor)
}
}
override fun response(url: String): String {
//模拟收到网络请求数据
val data = "{"id":"123456" , "name":"小明"}"
return data
}
}
class LoggerInterceptor() : Interceptor {
override fun intercept(url: String, chain: Interceptor.Chain): String {
println("打印请求前数据: ${url}")
//等发起网络请求后打印返回的网络上数据
//由于我们还有一个拦截器尚未处理,这里拿到的chain为EncodeInterceptor所对应的处理者realChainProcessor
//再接着就是执行processd方法
val response = chain.proceed(url, chain)
//等一切都执行完,数据都return 执行打印并返回到上一层
println("打印请求后数据: ${response}")
return response
}
}
class EncodeInterceptor : Interceptor {
override fun intercept(url: String, chain: Interceptor.Chain): String {
val newUrl = EncodeUtils.encode(url)
println("数据加密后发给服务器: ${newUrl}")
val response = chain.proceed(newUrl, chain)
//等一切都执行完,数据都return 执行打印并返回到上一层
println("数据解密返回给客户端")
val newResponse = EncodeUtils.decode(response)
return newResponse
}
}
//没意义加解密
object EncodeUtils {
fun encode(url: String): String {
return "${url}abcabc"
}
fun decode(url: String): String {
return "数据已解密 $url"
}
}
总结
大致的框架就出来了,从配置参数,到具体处理者的派发事件,各类各司其责,拦截器插拔方便,okhttp代码设计的确实好。 我上面的注释可能写的不是很清晰,强烈建议对着okhttp源码自己摸索一遍,或者把以上代码复制到编辑器里点击跳转走一遍。 之后各位同学想练习的话也可以模拟view的事件分发机制写个简单的过程,我这边就不展示了,也不是很难。
转载自:https://juejin.cn/post/7257434794925621307