kotlin - 类委托和属性委托
类委托
类委托是代理模式的应用。类委托的本质就是把这个类需要实现的部分委托给其他对象,相当于是借用其他对象的方法作为自己的实现。
示例代码如下:
interface Outputable {
fun output(msg: String)
var type: String
}
class DefaultOutput : Outputable {
override fun output(msg: String) {
println("默认输出方式:${msg}")
}
override var type: String = "输出设备"
}
//定义Printer类,指定构造参数out作为委托对象
class Printer(out: DefaultOutput) : Outputable by out
//指定新创建的类作为委托对象。
class Projector : Outputable by DefaultOutput() {
//重写output方法
override fun output(msg: String) {
println("投影设备输出:${msg}")
}
}
//使用
fun main(args: Array<String>) {
val output = DefaultOutput()
val printer = Printer(output)
printer.output("ppt")
println(printer.type)
val projector = Projector()
projector.output("word文档")
println(projector.type)
}
为类指定委托对象的方式有两种:
- 通过构造参数指定委托对象。
- 直接在类定义的by后新建对象。
属性委托
属性委托可以将多个类的类似属性统一交给委托对象集中实现。这样可以避免每个类都单独实现这些属性。
注意:kotlin不会为委托属性生成幕后字段、getter和setter方法,因此委托属性的所有细节都交由委托类去处理。
属性的委托对象,不需要实现任何接口,但是一定要提供operator
修饰的setValue()
和getValue()
方法(val
属性无需提供getValue()
方法)。
示例代码如下:
class PropertyDelegation{
var name:String by MyDelegation()
}
class MyDelegation{
private var _backValue:String ="默认值"
operator fun getValue(propertyDelegation: PropertyDelegation, property: KProperty<*>): String {
println("${propertyDelegation}的 ${property.name}属性执行get方法")
return _backValue
}
operator fun setValue(
propertyDelegation: PropertyDelegation,
property: KProperty<*>,
newValue: String
) {
println("${propertyDelegation}的 ${property.name}属性执行set方法 ,传入的参数为:${newValue}")
_backValue=newValue
}
}
//使用
fun main(args: Array<String>) {
val pd = PropertyDelegation()
//调用的是属性委托类的getValue方法
println(pd.name)
//调用的是属性委托类的setValue方法
pd.name="guojingbu"
println(pd.name)
}
上面输出的结果如下:
com.guojingbu.learning_kotlin.PropertyDelegation@300ffa5d的 name属性执行get方法
默认值
com.guojingbu.learning_kotlin.PropertyDelegation@300ffa5d的 name属性执行set方法 ,传入的参数为:guojingbu
com.guojingbu.learning_kotlin.PropertyDelegation@300ffa5d的 name属性执行get方法
guojingbu
属性监听
kotlin中的属性监听是通过属性委托给Delegates对象的observable()和vetoable()方法,这两个的返回值都是ReadWriteProperty<Any?,T>,这两个方法实现基本相同,唯一的区别是vetoable()的监听方法会返回一个Boolean类型的值,而observable()方法没有返回值。
observable()方法使用示例代码如下:
var observablePro:String by Delegates.observable("默认值"){
property, oldValue, newValue ->
println("$property 的 $oldValue 被修改为:$newValue")
}
//使用
fun main(args: Array<String>) {
println(observablePro)
observablePro="guojingbu"
println(observablePro)
}
上面代码输出结果如下:
默认值
var observablePro: kotlin.String 的 默认值 被修改为:guojingbu
guojingbu
vetoable()方法使用示例代码如下:
var vetoablePro:Int by Delegates.vetoable(1){
property, oldValue, newValue ->
println("${vetoablePro}的 ${property.name}属性执行set方法 ,传入的参数为:${newValue}")
newValue>oldValue
}
//使用
fun main(args: Array<String>) {
println(vetoablePro)
vetoablePro=2
println(vetoablePro)
}
上面代码输入结果如下:
1
var vetoablePro: kotlin.Int的 vetoablePro属性执行set方法 ,传入的参数为:2
2
通过上面的代码可以看出如果 newValue>oldValue 返回true,否则返回false,vetoablePro属性的值必须要比原属性大才能设置成功。
属性委托给map处理
kotlin中可以把属性委托给一个Map集合去管理。这样我们就可以通过map集合来访问对象的属性。
示例代码如下:
class Item(val map: Map<String, Any?>) {
val code: Int by map
val name: String by map
}
//使用
fun main(args: Array<String>) {
var item = Item(
mapOf(
"code" to 1,
"name" to "guojingbu"
)
)
println(item.code)
println(item.name)
println("-----------------------")
//其他程序可以通过map来访问数据。
println(item.map["code"])
println(item.map["name"])
}
上面这段程序的属性只能读,不能写。如果需要支持读写,可以把Map修改为MutableMap,然后把val关键字修改为var,就可以实现读写属性委托给map集合了。
变量的延迟初始化
通过kotlin的标准委托函数lazy()
来对变量延迟初始化。示例代码如下:
fun main(args: Array<String>) {
val name:String by lazy {
println("初始化变量name")
"guojingbu"
}
println("第一次访问:$name")
println("第二次访问:$name")
}
输出结果如下:
初始化变量name
第一次访问:guojingbu
第二次访问:guojingbu
注意:lazy函数只能用于val修饰的只读属性上。