前言
- 之前一直在忙隐私政策,最近鲜有时间去审查以前的代码,这一查才发现自己以前写的网络框架,问题还挺多,就进行了重构
- BasicLibrary Github地址:github.com/Peakmain/Ba…
旧代码分析
class RetrofitManager {
companion object {
//连接超时
private const val CONNECT_TIMEOUT = 60L
//阅读超时
private const val READ_TIMEOUT = 10L
//写入超时
private const val WRITE_TIMEOUT = 10L
fun buildOkHttpClient(): OkHttpClient {
val builder = OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)//设置连接超时
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//读取超时
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)//写入超时
builder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.hostnameVerifier(HostnameVerifier { _, _ -> true })
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val x509 = MyX509()
builder.sslSocketFactory(getSSLFactory(x509), x509)
}
prevBuildOkHttpClient(builder)
return builder.build()
}
/**
* 空方法,在构建okHttpClient之前可设置一些参数
*/
fun prevBuildOkHttpClient(builder: OkHttpClient.Builder) {
}
private fun getSSLFactory(x509TrustManager: X509ExtendedTrustManager): SSLSocketFactory {
val trustAllCerts = arrayOf<TrustManager>(x509TrustManager)
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
return sslContext.socketFactory
}
fun <T> createService(service: Class<T>, block: (service: Class<T>) -> T): T {
return block(service)
}
fun <T> createService(service: Class<T>, baseUrl: String): T {
val retrofit = retrofit2.Retrofit.Builder().baseUrl(baseUrl).client(buildOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
return retrofit.create(service)
}
fun <T> createData(observable: Observable<T>, apiStatus: ApiStatus<T>): Disposable {
apiStatus.before()
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe({ t ->
apiStatus.success(t)
}, { exception ->
exception.printStackTrace()
apiStatus.error(Exception(exception))
})
}
fun <T> createData(
observable: Observable<T>,
before: () -> Unit,
success: T.() -> Unit,
error: (Exception) -> Unit = {}
): Disposable {
before()
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe({ t ->
success(t)
}, { throwable ->
error(Exception(throwable))
})
}
fun <T> createBaseEntityData(
observable: Observable<BaseEntity<T>>,
apiStatus: ApiBaseStatus<T>
): Disposable {
apiStatus.before()
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe({ t ->
checkResult(observable, t, apiStatus)
}, { exception ->
checkError(exception, apiStatus)
})
}
private fun <T> checkError(exception: Throwable, apiStatus: ApiBaseStatus<T>) {
exception.printStackTrace()
apiStatus.error(Exception(exception))
}
private fun <T> checkResult(
observable: Observable<BaseEntity<T>>,
t: BaseEntity<T>,
apiStatus: ApiBaseStatus<T>
) {
apiStatus.baseData(t)
when (t.result) {
ErrorEnum.SUCCESS.code -> {
if (t.data != null) {
apiStatus.success(t.data)
} else {
apiStatus.isEmpty()
}
}
ErrorEnum.TOKEN_ERROR.code -> {
//token失效
apiStatus.tokenError(observable, apiStatus)
}
else -> {
apiStatus.ktxRunOnUiThread {
error(Exception(t.detail))
}
}
}
}
}
}
功能和架构
-
主要功能有两个:
- createService用于创建Retrofit的Service实例
- createData:用于进行网络请求,并利用rxjava进行主线程和工作线程切换
-
代码整体其实也没毛病,用起来也是很方便,但是从设计模式角度来说,有不少问题
- 单一职责:对类来说的,即一个类应该只负责一项职责。我们这里RetrofitManager负责职责有两个了,createService和createData
- createService方法主要用于创建Service的实例,通常来说都是ok的,但是在某些情况,我不想用你内部创建Service的方法,我想自己创建,此时该如何解决
- createData方法主要结合rxjava进行网络请求,apiStatus实际是个抽象类
interface BaseApiStatus<T> {
fun before()
fun success(t: T)
fun isEmpty()
fun loadMore(t: T, isRefresh: Boolean)
fun error(exception: Exception)
}
abstract class ApiStatus<T>:BaseApiStatus<T>{
override fun before() {
}
override fun isEmpty() {
}
override fun loadMore(t: T, isRefresh: Boolean) {
}
}
我们会发现此扩展性很差,比如:假设此时我们想自定义ApiStatus,例如新增一个token报错,那么此时的需求的RetrofitManager并不能满足我们的需求
单一问题解决
首先我们来单一的问题,既然说一个类只负责一项职责,那我们把CreateService这个方法单独拎出去,不就解决
class CommonRetrofitService {
fun <T> createService(service: Class<T>, baseUrl: String): T {
val retrofit = retrofit2.Retrofit.Builder().baseUrl(baseUrl)
.client(buildOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
return retrofit.create(service)
}
}
RetrofitManager直接使用
class RetrofitManager{
fun <T> createService(service: Class<T>, baseUrl: String): T {
return CommonRetoriftService().createService(service, baseUrl)
}
}
策略设计模式
上面代码虽然解决了单一问题,但是却只能用于CommonRetoriftService这一种,如果我们现在自定义一个BaseRetrofitService来创建Service的实例,应该怎么做,我们可以再建一个BaseRetrofitService,然后修改RetrofitManager
class RetrofitManager{
fun <T> createService(service: Class<T>, baseUrl: String): T {
return CommonRetoriftService().createService(service, baseUrl)
}
fun <T> createBaseService(service: Class<T>, baseUrl: String): T {
return BaseRetrofitService().createService(service, baseUrl)
}
}
- 可是对于客户端来说,总不能把源码下载下来进行修改吧,当然也可以哈,但是一般来说,不会这么做。那应该怎么做呢?
- 我们的需求是客户端可以自定义创建Service,那么我们就可以提供一个接口给用户,让用户去实现他要实现的逻辑,再让用户将策略发给我们就完成了
- 这里用到的设计模式是策略设计模式,大家直接看类图
- 那首先想到的是提供一个接口给用户
interface IRetrofitStrategy {
fun <T> createService(service: Class<T>, baseUrl: String): T
}
默认情况下我们可以自己创建一个策略,当用户不指定策略的时候,使用默认的策略
class CommonRetrofitStrategy : IRetrofitStrategy {
override fun <T> createService(service: Class<T>, baseUrl: String): T {
val retrofit = retrofit2.Retrofit.Builder().baseUrl(baseUrl)
.client(buildOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
return retrofit.create(service)
}
}
我们此时指定一个默认的策略,并提供策略给用户,具体实现有用户决定
class RetrofitManager {
companion object {
private var mStrategy: IRetrofitStrategy = CommonRetrofitStrategy()
fun executeStrategy(strategy: IRetrofitStrategy) {
this.mStrategy = strategy
}
fun <T> createService(service: Class<T>, block: (service: Class<T>) -> T): T {
return block(service)
}
fun <T> createService(service: Class<T>, baseUrl: String): T {
return mStrategy.createService(service, baseUrl)
}
}
}
桥接设计模式
- 上面我们已经对createService通过策略设计模式进行重构了,那么接下来我们来看看createData如何重构
- 我们直接看类图
- 我们一共两个变化模块
- 一个是ApiStatus,用户可能会自定义一些状态回调
- 一个是RetrofitData,用户可能会去自定义创建网络请求
- 我们将ApiStatus和RetrofitData单独分离出来,让他们单独处理 ApiStatus
interface BaseApiStatus<T> {
fun before()
fun success(t: T)
fun isEmpty()
fun loadMore(t: T, isRefresh: Boolean)
fun error(exception: Exception)
}
abstract class ApiStatus<T>:BaseApiStatus<T>{
override fun before() {
}
override fun isEmpty() {
}
override fun loadMore(t: T, isRefresh: Boolean) {
}
}
RetrofitData
abstract class AbstractRetrofitData<T> {
abstract fun createData(
observable: Observable<T>
): Disposable
}
class CommonRetrofitData<T> :
AbstractRetrofitData<T>{
override fun createData(observable: Observable<T>): Disposable {
apiStatus.before()
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe({ t ->
apiStatus.success(t)
}, { exception ->
exception.printStackTrace()
apiStatus.error(Exception(exception))
})
}
}
此时我们需要将两个单独变化的模块用桥建立关系,其实很简单,就是抽象类持有ApiStatus接口即可
abstract class AbstractRetrofitData<T>(apiStatus: BaseApiStatus<T>) {
protected var mBaseApiStatus: BaseApiStatus<T> = apiStatus
abstract fun createData(
observable: Observable<T>
): Disposable
}
RetrofitManager持有AbstractRetrofitData即可
class RetrofitManager {
....
fun <T> createData(
observable: Observable<T>,
retrofitData: AbstractRetrofitData<T>
): Disposable {
return retrofitData.createData(observable)
}
}
结尾
- 当我们在空闲的时候,还是要多抽时间去审查自己写的代码,多思考能不能换种方式去实现达到更好的解耦和效果
- 这是我的github:github.com/peakmain ,欢迎大家点赞哦