Kotlin学习之委托机制

类的委托

       委托模式可以很好的替代实现继承,kotlin本身支持需要零样板代码,一个类Derived 可以继承Base并委托它所有的public 方法到一个指定的类:

interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}


这个在父类后面的by指定b存储为Derived的内部对象,编译器会生成Base的所有方法寄于到b上。

属性的委托

       属性的委托指的一个类的某个属性的值不是在类中直接进行定义,而是由某个类的方法来进行 setter 和 getter。默认属性委托都是线程安全的。属性委托适合那些属性的需要复杂的计算但是计算过程可以被重用的场合。

定义一个被委托的类

       该类需要包含 getValue() 方法和 setValue() 方法,且参数 thisRef 为进行委托的类的对象,prop 为进行委托的属性的对象。

“`
class Delegate {

private var message = "Default Message"

operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
    return "${prop.name} = $message from $thisRef"
}

operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
    message = value
}

} “`

定义包含属性委托的类

class Example {
var msg: String by Delegate()
}

访问该属性
val e = Example()
println(e.msg)  //  msg = Default Message
e.msg = "New Message"
println(e.msg)  //  msg = New Message

       在使用属性委托时,被委托的类的方法(即接收者)的返回值必须与委托的属性相同或者其父类。

标准委托

       Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托。

lazy

       lazy 用于进行惰性加载,即第一次使用时才执行初始化的操作。

Observable

       observable 可以用于实现观察者模式。

定义包含被委托的属性的类

       Delegates.observable 接收三个参数:包含委托的属性的元数据的 KProperty 对象,旧值,新值。

class User {
var name: String by Delegates.observable("&lt;init value>") {
    prop, old, new ->
    if (old != new) {
        println("\\$old -> $new")
    }
}}
访问该属性
val user = User()
user.name = "first" //  <init value> -> first
user.name = "first"
user.name = "second"    //  first -> second

       也可以使用 vetoable 代替 observable,该方法拥有布尔类型的返回值,返回 false 的话可以取消对该属性的修改。
在以上 User 中定义一个新属性。

var age: Int by Delegates.vetoable(0) {
prop, old, new ->
println("$old -> $new")
if (new < 20) true else false
}

访问属性:

user.age = 10   //  0 -> 10
println(user.age)   //  10
user.age = 20   //  10 -> 20
println(user.age)   //  20
NotNull

       notNull 适用于那些无法在初始化阶段就确定属性值的场合。

class Foo {
var notNullBar: String by Delegates.notNull<String>()
}foo.notNullBar = "bar"
println(foo.notNullBar)

       需要注意,如果属性在赋值前就被访问的话则会抛出异常。

以 Map 形式保存属性的值

       Kotlin 中有一种特别的委托,可以以 Map 作为一个类的构造方法的参数,访问该类的属性就是访问该 Map 的键值对。这种做法非常类似 Groovy 中的带名构造方法。
要实现这一功能需要得意于 Kotlin 内置的属性的扩展方法 kotlin.properties.getValue
例:

import kotlin.properties.getValue

class Person(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}

可以像普通类一样访问其各个属性:

val person = Person(mapOf(
    "name" to "John",
    "age" to 25
))
println(person.name)
println(person.age)

       对于可变值,可以使用 MutableMap 代替,并导入扩展方法 kotlin.properties.setValue。

import kotlin.properties.setValue

class MutablePerson(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int     by map
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值