类委托
类委托就是 现在有一个类需要实现某接口,发现有一个对于这个接口已经实现好的类,可以直接将这个现成的类拿来使用,也就是说本类继承某接口的任务委托了一个现成已经实现好的类的实例。
interface BASE{
fun say();
}
interface BASE2{
fun say2();
}
class SUB: BASE, BASE2{
override fun say() {
println("Hello World");
}
override fun say2() {
println("2222");
}
}
class A: BASE by SUB();
fun main(args: Array<String>) {
var a = A();
a.say();
}
属性委托
类中的属性也可以委托给现成的类实例,但是如果要是想更改这些属性的值,实际上是对委托对象内部的操作,需要在被委托的类中实现getValue,setValue。
通过thisRef与p我们定位到我们使用委托对象的那个类中的每个属性。
class BASE {
var x: Int by MY();
/*
等价于 var x$MY = MY()
get() = x$MY.getValue(this, BASE::x)
set(value) = x$MY.setValue(this, BASE:x, value);
*/
var y: Int by MY();
}
class MY {
var _x:Int = 0;
var _y:Int = 0;
operator fun getValue(thisRef:BASE, p:KProperty<*>): Int {
when(p.name) {
"x" -> {
return _x;
}
"y" -> {
return _y;
}
else -> {
return 0;
}
}
}
operator fun setValue(thisRef: BASE, p:KProperty<*>, value:Int){
when(p.name) {
"x" -> {
_x = value;
}
"y" -> {
_y = value;
}
}
}
}
fun main(args: Array<String>) {
var b = BASE();
b.x = 100;
b.y = 24;
println("(" + b.x + "," + b.y + ")");
}
延迟属性
Kotlin提供了一个lazy()函数,该函数接受一个lambda表达式作为参数,并返回一个Lazy对象作为委托对象。有个特点就是第一次使用这个属性的时候会执行整个lambda表达式,第二次以后执行直接返回第一次的返回值。只有val修饰的只读属性可以使用lazy标记。
class BASE {
val str by lazy {
println("Hello World");
"HELLO"
}
}
fun main(args: Array<String>) {
var base = BASE();
base.str;
}
属性监听
Kotlin在kotlin.properties包中提供了Delegates对象声明(单例)。
这个对象提供了两种方法observable()与vetoable()两个方法用于实现属性监听。
函数会返回ReadWriteProperty<Any?, T>类型的委托属性。两个属性的区别在于第一个是无条件的进行赋值,第二个是有条件的赋值,返回为假就不赋值。
class BASE {
var x:Int by Delegates.observable(0) {
prop, old, new ->
println(""+prop+"属性的值从"+old+"改为"+new);
}
var y:Int by Delegates.vetoable(0) {
prop, old, new ->
println(""+prop+"属性的值从"+old+"改为"+new);
old < new;
}
}
fun main(args: Array<String>) {
var base = BASE();
base.x = 100;
base.y = -1;
println(base.y);
}
委托工厂
属性在初始化时自动回调委托工厂的provideDelegate()方法,然后返回一个ReadWriteProperty<MyTarget,String>对象。
然后通过provideDelegate()返回一个重写包含getValue()与setValue()的对象就可以。
class BASE {
var x: Int by MDelegate();
}
class MDelegate{
operator fun provideDelegate(thisRef:BASE, prop:KProperty<*>):ReadWriteProperty<BASE,Int> {
return MyDelegate();
}
class MyDelegate: ReadWriteProperty<BASE,Int> {
var _x = 0;
override fun getValue(thisRef: BASE, property: KProperty<*>): Int {
return _x;
}
override fun setValue(thisRef: BASE, property: KProperty<*>, value: Int) {
_x = value;
}
}
}
fun main(args: Array<String>) {
var base = BASE();
base.x = 1;
println(base.x);
}