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学习笔记——委托属性)