問題場景:
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/