这可能是我目前看的最舒服的Kotlin数据Handle类了

前言

毕竟是第一次在这上面写东西,感觉开头不写点什么东西不太好,不太严谨。那我就来个严谨的吧。在我们开发当中不可避免的会与数据打交道,数据可以来自network,local...因此很快就会想到一个模版:

kotlin 复制代码
class XxxRep {
    suspend fun getData(): Result<YourData>
 }
 
class XxxUseCase(
    private val xxRepImpl: XxxRep
) {
    operator fun invoke() {
        xxxRepImpl.getData()
        ///
    }
}

有木有那种感觉了.接下来我们就要针对结果的success和failure去进行处理就行了,现在我要讲的就是包装这个Result。

a. sealed interface

这里先看一下代码

kotlin 复制代码
    sealed class Result<T>(val data : T?= null, val message: String? = null) {
        data class Success<T>(val data: T?): Result<T>(data)
        data class Error<T>(val message: String? = null, val data: T? = null): Result<T>(data, message)
    }

是不是通用的密封类看起来觉得还行,但是我现在不用它了。理由无他,我不想写那么多的参数。开玩笑的,一方面有这理由,还有一方面就是我认为具体的message不应该是string直接在data层获取并一步步传递到domain层再到presentation层,我们应该包装成一种状态的形式用于表示error。大白话就是用个枚聚类表示error状态,然后定义些许个string。

csharp 复制代码
sealed interface Error  
  
typealias RootError = Error  
  
sealed interface Result<out D, out E : RootError> {  
    data class Success<out D, out E : RootError>(val data: D) : Result<D, E>  
    data class Error<out D, out E : RootError>(val error: E) : Result<D, E>  
}  
  

我来解释一下👀 首先我定义了一个顶层Error,这意味着我们后续所有模块中的Error都是它的弟弟,哦不,儿子。

kotlin 复制代码
sealed interface DataError: Error {  
    enum class NetWorkError : DataError {  
        NO_INTERNET,  
        TOO_MANY_REQUESTS,  
        UNEXPECTED_TOKEN,  
        PAYLOAD,  
        REQUEST_TIMEOUT  
    }  

    enum class LocalError: DataError {  
        SERIALIZATION,  
        UNKNOWN  
        }  
}

sealed interface XxxUseCaseError : Error {  
    enum class FinalError : XxxUseCaseError {  
        ABC_ERROR,  
        CHUNK_ERROR  
    }  
}

然后我用typealias取了个别名,这个没有啥特别含义啊,就是单纯命名以及泛型名称一样会报错罢了。 最后和之前的一样,定义了data,error并用out修饰,意思就是提前口头警告你小子这些个参数改不了,只能给爷乖乖读。

b. Data

核心已经结束了,剩下的就是怎么串联起来了,我们只要将上面的rep的改一下。

kotlin 复制代码
interface AuthRep {  
    suspend fun registerUser(name: String?): Result<User, DataError>  
}  
  
class NetAuthRepImpl: AuthRep {  
    override suspend fun registerUser(name: String?): Result<User, DataError> {  
        return Result.Error(DataError.NetWorkError.NO_INTERNET)  
    }  
}  
  
class LocalAuthRepImpl: AuthRep {  
    override suspend fun registerUser(name: String?): Result<User, DataError> {  
        return Result.Error(DataError.LocalError.SERIALIZATION)  
    }  
}  
  
data class User(  
    val id: Int,  
    val name: String,  
    val email: String  
)

剩下的大家懂得都懂了,我们只要在viewModel或者useCase中去使用when分别处理结果就行了。

scss 复制代码
class RegisterUserUseCase(  
    private val netAuthRepImpl: AuthRep = NetAuthRepImpl(),  
    private val localAuthRepImpl: AuthRep = LocalAuthRepImpl()  
) {  
  
suspend fun registerUser(name: String) {  
    when(val result = netAuthRepImpl.registerUser(name)) {  
    is Result.Error -> { handleNetWorkError(result.error) }  
    is Result.Success -> TODO()  
    } 
}  
  
private fun handleNetWorkError(error: DataError) {  
    when(error) {  
        DataError.LocalError.SERIALIZATION -> TODO()  
        DataError.LocalError.UNKNOWN -> TODO()  
        DataError.NetWorkError.NO_INTERNET -> TODO()  
        DataError.NetWorkError.TOO_MANY_REQUESTS -> TODO()  
        DataError.NetWorkError.UNEXPECTED_TOKEN -> TODO()  
        DataError.NetWorkError.PAYLOAD -> TODO()  
        DataError.NetWorkError.REQUEST_TIMEOUT -> TODO()  
    }  
}  
  

到这里好像一下子就明朗起来了✌️,结束!

塔塔开

实在想不出来取什么标题了,最近刚又补完进击的巨人,就鬼使神差了。到这里我们再做一个扩展,其实对于我们来说,前期的努力是为了后期的装杯,因此到这里还没完。可以看到我的useCase中只用了一个netAuthImpl的方法,其实在我们实际场景中我们基本避免不了网络获取数据,本地存储数据这一个单向流操作。因此我们又很容易写出这样的:

kotlin 复制代码
when(val result = netAuthRepImpl.registerUser(name)) {  
        is Result.Error -> { handleNetWorkError(result.error) }  
        is Result.Success -> {  
        localAuthRepImpl.registerUser(result.data.name)  
    }  
}
    

MD确实好像也没啥问题,也不错,淦,那要不结束了吧。怎么可能,我这个例子比较简单罢了。我想要的是一种简洁明了跟读手册一样啊くそやろ!

kotlin 复制代码
inline fun <D, E : RootError, R> Result<D, E>.andThen(block: D.() -> Result<R, E>): Result<R, E> {  
    return when (this) {  
        is Result.Error -> {  
            Result.Error(this.error)  
        }  

        is Result.Success -> {  
            block(this.data)  
        }  
    }  
}  
  
  
inline fun <D, E : RootError> Result<D, E>.onSuccess(action: (value: D) -> Unit): Result<D, E> {  
    if (this is Result.Success) {  
        action(this.data)  
    }  
    return this  
}  
  
inline fun <D, E : RootError> Result<D, E>.onFailure(action: (error: E) -> Unit): Result<D, E> {  
    if (this is Result.Error) {  
        action(this.error)  
    }  
    return this  
}

fun Result<*, DataError>.asUnitText() {  
if (this is Result.Error) {  
    when (this.error) {  
        DataError.LocalError.SERIALIZATION -> "Ooops, There is some error when serializing the data!"  
        DataError.LocalError.UNKNOWN -> TODO()  
        DataError.NetWorkError.NO_INTERNET -> TODO()  
        DataError.NetWorkError.TOO_MANY_REQUESTS -> TODO()  
        DataError.NetWorkError.UNEXPECTED_TOKEN -> TODO()  
        DataError.NetWorkError.PAYLOAD -> TODO()  
        DataError.NetWorkError.REQUEST_TIMEOUT -> TODO()  
    }  
    } else {  
        throw Exception()  
    }

我扩展了Result方法,很简单,简单的让我误以为自己很厉害了。

kotlin 复制代码
return netAuthRepImpl.registerUser(name).andThen {  
    localAuthRepImpl.registerUser(this.name)  
}.onSuccess {  
    // do works  
}.onFailure {  
    handleNetWorkError(it)  
}

简洁明了吧,over~😏

最后

其中可能涉及了一些架构术语,像domain,usecase诸如此类,其实这是来自整洁架构的定义。有兴趣的朋友可以了解一下,我简单介绍一下,核心就是将整个结构分为三部分,数据,操作,显示三个域,每个域互相隔离。真特么简单,这个介绍😄(我自己先吐槽一下)。

作为一个老看客了,距离上一次写技术博客还是疫情年上大学的时候,我也不知道为什么突然写了,想做就做了,可能人就是这样的生物吧。

少年时你听到人们说应该欣赏日落,但你忙于探索世界,不能静静地坐下来观赏。再后来,你抗拒本应该感觉得到的情感,斥之为庸俗。随着年龄的增长,你不再关心日落在别人眼中的是否庸俗。你用自己的眼睛去看它,内心充满感激和欣喜。

相关推荐
xvch1 小时前
Kotlin 2.1.0 入门教程(五)
android·kotlin
xvch5 小时前
Kotlin 2.1.0 入门教程(七)
android·kotlin
zhangphil7 小时前
Android BitmapShader简洁实现马赛克,Kotlin(一)
android·kotlin
五味香14 小时前
Java学习,查找List最大最小值
android·java·开发语言·python·学习·golang·kotlin
五味香2 天前
Java学习,List截取
android·java·开发语言·python·学习·golang·kotlin
xvch2 天前
Kotlin 2.1.0 入门教程(三)
android·kotlin
小李飞飞砖2 天前
kotlin的协程的基础概念
开发语言·前端·kotlin
深色風信子3 天前
Kotlin Bytedeco OpenCV 图像图像49 仿射变换 图像裁剪
opencv·kotlin·javacpp·bytedeco·仿射变换 图像裁剪
五味香3 天前
Java学习,List移动元素
android·java·开发语言·python·学习·kotlin·list
studyForMokey3 天前
【Android学习】Kotlin随笔
android·学习·kotlin