委托属性
特点:常见的属性类型,交给委托类统一实现,避免每个类都要单独重复实现一次
语法: val/var <属性名>: <类型> by <表达式>
by后面的表达式是委托,会被委托给它用operator修饰的getValue()函数 (于setValue()函数 ->对应于var属性)
属性委托要求
val声明的,委托必须提供一个名为getValue的函数,接收参数:
- thisRef 必须与属性所有者类型相同或超类型(对应扩展函数指被扩展类型)
- property 必须是类型KProperty<*>
var声明的, 还必须提供一个setValue函数
- thisRef
- property
- newValue 必须与属性同类型或者它的子类型
委托类可以实现包含operator方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
kotlin标注库提供的委托
-
延迟属性的lazy
lazy接收一个lambda 并返回Lazy实例函数。第一调用get() 执行lambda,并记录结果,后续get()返回记录的结果。
lazy属性求值默认是同步锁的(synchronized) ,只在一个线程中计算,所有线程会看到相同的值。还有其它莫斯
LazyThreadSafetyMode.PUBLICATION 和 LazyThreadSafetyMode.NONE
val lazyValue: String by lazy{
....
return "string"
}
- 可观察属性Observable
Delegates.observable() 接收两个参数:初始值和修改是处理程序。每当给属性赋值后回执处理程序
处理程序有三个参数: 被赋值的属性,旧值,新值
class User{
var name: String by Delegates.observable("no name"){
pro,old,new -> print("$old -> $new")
}
}
- 把属性存储在映射中
映射map里存储属性的值(字符串key <—> 属性的名称)
class User(val map: Map<String,Any?>){
val name: String by map
val age: Int by map
}
val user - User(mapOf{
"name" to "xxxx"
"age" to 20
})
- 局部委托属性
将局部变量声明为委托属性, 减少不必要的计算
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
提供自定义委托
通过定义provideDelegate操作符, 扩展创建属性实现所委托的对象逻辑。
如果by右侧使用的对象将 provideDelegate定义为成员函数或扩展函数,那么会调用该函数来创建委托实例。
class DuplicateDataFragment : BaseRxFragment(){
val duplicateDatas: DuplicateCheckDatas by bindArgument("duplicateDatas")
companion object {
fun newInstance(duplicateDatas: DuplicateCheckDatas): DuplicateDataFragment {
val fragment = DuplicateDataFragment()
val bundle = Bundle()
bundle.putSerializable("duplicateDatas", duplicateDatas)
fragment.arguments = bundle
return fragment
}
}
}
在xxx.kt文件中看bindArgument实现
fun<U,T> Activity.bindExtra(key: String) = BindLoader<U,T>(key)
fun <U, T> Fragment.bindArgument(key: String) = BindLoader<U, T>(key)
fun <U, T> android.app.Fragment.bindArgument(key: String) = BindLoader<U, T>(key)
class BindLoader<in U, out T>(private val key: String){
operator fun provideDelegate(thisRef:U, prop: KProperty<*>): ReadOnlyProperty<U,T>{
// 创建委托
return IntentDelegate(key)
}
}
private class IntentDelegate<in U, out T>(private val key: String): ReadOnlyProperty<U,T>{
override fun getValue(thisRef: U, property: KProperty<*>): T {
return when(thisRef){
is Fragment -> thisRef.arguments?.get(key) as T
is android.app.Fragment -> thisRef.arguments?.get(key) as T
else -> (thisRef as Activity).intent?.extras?.get(key) as T
}
}
}
类委托
两个对象参与处理同一个请求,接受请求的对象将请求委托给另外一个对象来处理。是实现继承的一种替代方式。
kotlin可以零样板代码地原生支持。
class Derived(b: Base) : Base by b
by字句表示b将会在Derived中内部存储,并且编译器将生成转发给b的所有Base的方法。
覆盖由委托实现的接口成员
interface Base{
fun printMessage()
}
class BaseImpl(val x: Int): Base{
override fun printMessage(){
print(x)
}
}
class Dervied(b: Base): Base by b{
override fun printMessage(){
print("abc")
}
}
编译器会使用override覆盖实现而不是委托对象中的。