持续创作,加速成长!这是我参与「掘金日新计划 · 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设计模式
构造者设计模式使用非常普遍,比如okhttp
、AlertDialog
等等,在我看来构建者设计模式使用的目的有两个:
- 有选择性的参数动态配置
- 参数合法性校验
而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值的安全隐患。