kotlin学习笔记——委托属性

Kotlin学习笔记系列:http://blog.csdn.net/column/details/16696.html


委托属性

kotlin提供了将属性委托到一个类的方法,就是委托属性。
当我们使用属性的get和set方法时,属性委托的getValue和setValue就会被调用。
属性委托的结构如下:
class Delegate : ReadWriteProperty{
     override fun getValue(thisRef: Any?, property: KProperty<*>): T{
          return ...
     }

     override fun setValue(thisRef: Any?, property: KProperty<*>, value: T){
          ...
     }
}
其中T是委托属性的类型,getValue接收一个类的引用和一个属性的元数据,setValue多接收一个设置的值。

使用by关键字来委托属性,如下:
class Example {
     var p: String by Delegate()
}




一、标准委托

kotlin标准库中有一系列标准委托,我们可以直接使用,可以应付大部分情况。当然我们也可以自定义委托。

1、Lazy

需要提供一个lambda,当第一次执行getValue时会执行这个lambda进行初始化,之后再调用getValue会返回同一个值。所以委托的属性可以延迟进行初始化,在真正使用前可以不必初始化。如:
class App : Application{
     val database: SQLiteOpenHelper by lazy{
          MyDatabaseHelper(applicationContext)
     }

     override fun onCreate(){
          super.onCreate()
          var db = database.writableDatabase
     }
}
所以只要当在onCreate中使用时才去初始化,而这时候applicationContext已经存在了。
lazy是线程安全的。如果不担心多线程问题,可以使用lazy(LazyThreadSafeMode.NONE){ ... }来提高性能
同时要注意委托lazy的属性必须是不可变变量,既val修饰,如果用var修饰会报编译错误

2、Observable

这个委托会检测值的变化,当属性的set方法被调用,会自动执行我们指定的lambda表达式。一旦属性被赋予了新值,我们就会接收到被委托的属性、旧值和新值。如:
class ViewModel(val db: MyDatabase){
     var name by Delegates.observable(""){
          d, old, new -> db.saveChange(this, new)
     }
}
这个例子中一旦值被修改就会保存到数据库中。
注意Delegates.observable("")中传的是设定的初始值

3、Vetoable

这是一个特殊的Observable,通过指定的lambda表达式来确定是否保存新值。如
var name by Delegates.vetoable(0){
     d, old, new -> new >= 0
}
例子中表示只有新值是正数时才保存

4、NotNull

有时候使用属性前可能未初始化,比如像activity这类无法在构造函数中初始化属性的情况。通常我们会定义一个可为null的变量并初始化为空,在每次使用之前做判空。kotlin中还有另外一种方法,使用委托属性NotNull,如:
var name: String by Delegates.notNull()
如果赋值前使用时会抛出一个错误。
(目前这个方案与初始化为Null一样都在使用前要进行判断,否则抛出错误,所以不太能get到使用的点在哪里)

5、从Map中委托值

可以将属性委托到一个map,属性的值会从map中获取,属性的名字对应map中的key。
注意不同版本的区别
在有的版本中,需要import kotlin.properties.getValue 或 kotlin.properties.setValue
在kotlin-stdlib:1.1.2-4中则不需要,但是不能直接使用map,如:
class Config (map: HashMap){
  var name: String by map
  var id: Int by map
}

var config = Config(hashMapOf(
     "name" to "test",
     "id" to 12
))



二、自定义委托

参照文章开始
自定义委托必须实现ReadWriteProperty或ReadOnlyProperty,取决于被委托对象是var还是val。
然后重写setValue和getValue方法即可。
使用时可以直接使用(参考文章开始)
也可以像Delegates那样集中定义函数,如:
object DelegatesExt{
     fun notNullSingle() : ReadWriteProperty = NotNullSingle()   //NotNullSingle是我们自定义的委托

}



你可能感兴趣的:(Kotlin,Kotlin学习笔记)