我是如何Kotlin优化项目代码(2)

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

接下来会将笔者平常项目开发过程中,借助于Kotlin实现的比较好的代码实践分享给大家。

更简便弹出toast

先看下原生弹出toast的代码:

Toast.makeText(this, "haha", Toast.LENGTH_SHORT).show()
复制代码

写起来有点繁琐,接下来我们就会扩展函数封装下:

fun String.toast() {
    Toast.makeText(MainApp.mApplication, "", Toast.LENGTH_SHORT).show()
}
复制代码

这样调用就非常方便了:

"haha".toast()
复制代码

当然由于Toast弹出的时间有两种,这里只是封装了Toast.LENGTH_SHORT,对于Toast.LENGTH_LONG可以再封装一个扩展方法,

fun String.longToast() {
    Toast.makeText(MainApp.mApplication, "", Toast.LENGTH_LONG).show()
}
复制代码

或者在上一个扩展方法toast()的基础上增加一个默认参数:

fun String.toast(isLong: Boolean = false) {
    Toast.makeText(MainApp.mApplication, "", if (isLong) Toast.LENGTH_LONG else
        Toast.LENGTH_SHORT).show()
}
复制代码

多对象判空逻辑校验优化

日常编程中,应该会经常碰到下面这种情况,需要对多个对象判空才能执行某个逻辑:

fun test(other1: Other1?, other2: Other2?, other3: Other3?) {
    if (other1 != null && other2 != null && other3 != null) {
        //执行某种逻辑
    }
}
复制代码

这样写起来就很麻烦,而且一旦判空的对象多了,更是恐怖,借助于扩展函数+vararg可以封装如下函数:

fun requireNotNull(vararg obj: Any?, block: () -> Unit) {
    if (obj.filterNotNull().isNotEmpty()) {
        block()
    }
}
复制代码

基于上面封装就可以这样实现代码:

fun test(other1: Other1?, other2: Other2?, other3: Other3?) {
    requireNotNull(other1, other2, other3) {
        //执行非空的逻辑
    }
}
复制代码

上下对比,是不是非常明显,下面的更加优雅简单。

布尔判断逻辑校验优化

日常编码过程中,我们肯定会写出下面的代码:

fun test2(name: String, age: Int, other1: Other1?) {
    if (name.isNotEmpty() && age == 20 && other1 == null) {
        //执行某种逻辑
    }
}
复制代码

上面这样写一点毛病也没有,但是我们可以借助于invoke运算符重载标识去掉每次每次逻辑判断的if这两个字母的:

operator fun Boolean.invoke(block: () -> Unit) {
    if (this) {
        block()
    }
}
复制代码

以后就可以骚气的这样写判断:

fun test2(name: String, age: Int, other1: Other1?) {
    (name.isNotEmpty() && age == 20 && other1 == null) {
        //执行某种逻辑
    }
}
复制代码

默认参数+命名参数+require校验代替Build设计模式

构造者设计模式使用非常普遍,比如okhttpAlertDialog等等,在我看来构建者设计模式使用的目的有两个:

  • 有选择性的参数动态配置
  • 参数合法性校验

而Kotlin的默认参数+命名参数就可以轻松实现有选择性的参数动态配置,比如,定义下面这样一个数据类:

data class Other1(
    val name: String = "",
    val age: String = "",
    val content: String = "",
    val type: Int = -1,
    val card: String = "",
    val child: String = "",
) {
}
复制代码

首先给每个参数默认值,这样如果没有外部配置该参数时,使用默认值不产生负面效果,然后外部需要赋值时,直接指定对应的参数名进行赋值即可:

fun test3() {
    val other = Other1(
        age = "15",
        type = 10
    )
}
复制代码

接下来还有一个参数合法性校验的,我们可以定义一个require方法实现:

fun require(condition: Boolean, block: () -> Unit) {
    if (!condition) {
        block()
    }
}
​
fun require(condition: Boolean, message: String = "") {
    if (!condition) {
        throw IllegalArgumentException(message)
    }
}
复制代码
  • 第一个方法是用来检验参数不符合逻辑时,需要进行修正的代码逻辑;
  • 第二个方法是用来校验参数不符合逻辑时,直接抛出异常处理,适合比较严苛的校验场景

然后看下在Other1类中的使用:

    init {
        //修正
        require(content == "data") {
            content = ""
        }
        //抛出异常
        require(age > "10", "age must > "10"")
    }
复制代码

其实kotlin中有帮助我们定义require校验方法,但是不符合条件就抛出异常感觉不太号,所以就自定义了者两种校验方法。

经过上面的处理,构建者设计模式能实现的事情,使用Kotlin某些特性就能代替,使用起来也是十分的方便简单。

请注意:定义数据类时给每个构造参数增加默认值是一个比较好的习惯,尤其是涉及到与Gson的序列化和反序列化,能够减少null值的安全隐患。

猜你喜欢

转载自juejin.im/post/7102052006366380062
今日推荐