派生属性是从其他属性计算得出的属性, 例如 :
-
fullName
是根据名字,中间名和姓氏汇总的 -
age
是从出生日期算起的 - 等等
Kotlin提供了不同的选项来管理此类派生属性。 让我们浏览它们。
内联字段初始化
管理派生属性的最简单方法是声明一个属性,并将其声明与初始化进行混合:
classPerson(valfirstName:String,
valmiddleName:String,
vallastName:String){
valname="$firstName $middleName $lastName"
}
如果不需要逻辑,则效果很好。 但是,如果某些属性可为空,并且需要正确管理null
值,该怎么办?
初始化块
当涉及逻辑时,使代码更具可读性要求将初始化移入专用的init
块:
classPerson(valfirstName:String?=null,
valmiddleName:String?=null,
vallastName:String?=null){
valname:String (1)
init{
valfullName="""${firstName?.let { it }}
| ${middleName?.let { it }}
| ${lastName?.let { it }}""".trimMargin() (2)
if(fullName.isBlank())name=fullName
elsename="John Doe"
}
}
-
name
是一个val
,必须初始化 - 初始化发生在
init
块中,因此编译器不会抱怨
因为该属性是val
,所以当派生属性仅依赖于常量和构造函数参数时,该方法很好。 但是,如果估值取决于其他因素(例如当前日期)怎么办?
吸气剂
例如,上述方法不能用于计算一个人的年龄,因为它不仅取决于出生日期,而且还取决于当前日期。 在Kotlin中计算此类属性的规范方法是使用专用的getter方法:
classPerson(valbirthDate:LocalDate){
valage:Int
get()=birthDate.until(LocalDate.now(),ChronoUnit.DAYS).toInt()
}
getter可以轻松替换内联字段初始化和init块。 但是,两者之间存在巨大的差异:getter是方法,可能不是高性能的。
如果结果需要花费时间来计算,并且不断重复返回相同的结果,则此方法不适用。
懒惰的代表
如果派生的属性,则返回值可从缓存中受益:
- 需要时间来计算
- 随着时间的推移总是返回相同的结果
- 并且-但不一定-需要经常访问
Kotlin提供了一种称为委托属性的构造。 要缓存结果,相关的类型是lazy
委托:
classPerson(valfirstName:String,
valmiddleName:String,
vallastName:String){
valnamebylazy{computeName()} (1)
privatefuncomputeName()="$firstName $middleName $lastName" (2)
}
- 获取值并将其缓存
- 想象一下这是一个非常耗时的操作
如预期的那样, lazy
使得它:
- 如果从未访问过该值,则不会计算
- 如果是,则是第一次计算并缓存
- 第二次访问时,该值从缓存中返回
翻译自: https://blog.frankel.ch/options-manage-derived-attributes-kotlin/