likes
comments
collection
share

通过okhttp拦截器demo加深对责任链模式的理解

作者站长头像
站长
· 阅读数 61

责任链模式的思想

事件或者数据传递到第一个处理者身上,每一个处理者都持有下一个处理者的引用,从第一个处理者开始决定:

  1. 拦截数据自己处理,不传递给后面的处理者

  2. 不拦截数据,加工数据后传递给下一个处理者

  3. 。。。重复步骤1,2

  4. 如果都没人拦截,数据一直返回到最初的地方(通过return的方式,后面通过例子演示)

通过okhttp拦截器demo加深对责任链模式的理解

例子

建议把代码复制到编辑器里点击跳转走一遍,更容易理解

像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
评论
请登录