问题场景:
retrofit大家都很熟悉.创建使用大概如下.
(1) 定义接口请求类
interface RetrofitService {
@GET("/posts")
fun getPosts(): Deferred<Response<List<Post>>>
}
(2)创建接口实体类
object RetrofitFactory {
const val BASE_URL = "https://jsonplaceholder.typicode.com"
fun createRetrofitService(): RetrofitService = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.client(getClient())
.build()
.create(RetrofitService::class.java)
private fun getClient(): OkHttpClient =
OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}
(3)调用
object NetRepository {
private val service: RetrofitService by lazy {
RetrofitFactory.createRetrofitService()
}
fun getDeferredPost() = service.getPosts()
}
现在我现在我的应用里面对接的网络接口只有一种类型就是RetrofitService,假设这个Service是专门处理商品类型的网络请求.如果
这时候需求变更,需要在添加用户登录,支付等接口功能该如何设计代码呢?
方案一
BASE_URL是没变么,直接在RetrofitService接口类写完剩下的接口不就完事儿了.
分析:
这样是可以.但是不满足java设计模式的单一职责你的接口有关于支付的,有关于的用户信息的,又有关于支付相关的.这样代码不清爽.好你说可以忍受反正自己挖的坑自己含着泪也得填.如果连域名都变了,该怎么办?
方案二
那我创建多个接口对象就好了
object RetrofitFactory {
const val BASE_URL = "https://jsonplaceholder.typicode.com"
const val BASE_URL1 = "https://jsonplaceholder.typicode.com1"
fun createRetrofitService(url: String): RetrofitService =
createRetrofit(BASE_URL).create(RetrofitService::class.java)
fun createRetrofitService1(url: String): RetrofitService1 =
createRetrofit(BASE_URL1).create(RetrofitService1::class.java)
private fun createRetrofit(url: String): Retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.client(getClient())
.build()
private fun getClient(): OkHttpClient =
OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}
分析:
确实解决了方案1的痛点,但是2个写起来看起来还不费事,试试看10个,20个..这样代码里面充满了大量类似的代码.我们是不是可以合并同类项目呢?
方案三
这边很有人就想起来泛型,但是在java里面有泛型擦除,但是到了kotlin我们就可以解决了这个问题.koltin里面有个保留关键子reified翻译成中文是具体化.它的作用就是这个是为了满足inline特性而设计的语法糖,因为给函数使用内联之后,编译器会用其函数体来替换掉函数调用,而如果该函数里面有泛型就可能会出现编译器不懂该泛型的问题,所以引入reified,使该泛型被智能替换成对应的类型.
object RetrofitFactory {
const val BASE_URL = "https://jsonplaceholder.typicode.com"
const val BASE_URL1 = "https://jsonplaceholder.typicode.com1"
inline fun <reified T> createRetrofitService(url: String): T =
createRetrofit(url).create(getRetrofitService<T>())
fun createRetrofit(url: String): Retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.client(getClient())
.build()
inline fun <reified T> getRetrofitService(): Class<T> = T::class.java
private fun getClient(): OkHttpClient =
OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}
调用类
object NetRepository {
private val service: RetrofitService by lazy {
RetrofitFactory.createRetrofitService<RetrofitService>(RetrofitFactory.BASE_URL)
}
private val service1: RetrofitService1 by lazy {
RetrofitFactory.createRetrofitService<RetrofitService1>(RetrofitFactory.BASE_URL1)
}
fun getPost() {
service.getPosts()
}
fun getPost1() {
service1.getPosts()
}
}
分析:
通过泛型T直接获得具体类RetrofitService,RetrofitService1.这样以后增加接口,只要写接口类,域名url,其他代码都可以保持不变.减少了后期维护的工作量.代码请见https://github.com/ThinkJarvis/Mvvm/