Kotlin笔记7-Delegation 和 Delegated Properties

一、Delegation 类的代理

代理模式被证明是实现继承的一个很好替代方案,代理模式使得我们可以用聚合来替代继承,将代理和真实实现分离开来,以达成解耦的目的。

Kotlin对代理模式内置支持,且零模版代码化。下面代码中代理类Derived通过实现Base接口,把其所有public的成员代理给一个指定的对象b

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print()
}

上面代码中,对象b会被保存在Derived类内部,并且编译器会生成接口Base中的所有方法,来调用对象b的相应方法。

Derived类反编译成的Java代码如下:从中可以看出Kotlin的内置代理支持,实现了零模版代码。

public final class Derived implements Base {
   // $FF: synthetic field
   private final Base $$delegate_0;

   public Derived(@NotNull Base b) {
      Intrinsics.checkParameterIsNotNull(b, "b");
      super();
      this.$$delegate_0 = b;
   }

   public void print() {
      this.$$delegate_0.print();
   }
}

⚠️注意:如果在代理类中手动实现了接口中的某一个方法或者属性变量,则最终调用时,会覆盖代理对象中的方法和变量

interface Base {
    val message: String
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override val message = "BaseImpl: x = $x"
    override fun print() { println(message) }
}

class Derived(b: Base) : Base by b {
    // This property is not accessed from b's implementation of `print`
    override val message = "Message of Derived"
    override fun print() { println("abc") }
}

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    val derived = Derived(b)
    derived.print()
    println(derived.message)
}

//输出
abc
Message of Derived

二、Delegated Properties 属性的代理

属性代理赋予了属性富有变化的活力,有以下三种属性委托方式:

1. 延迟属性 lazy properties : 其值只在首次访问时计算

2. 可观察属性 observable properties :监听器会收到有关此属性变更的通知

3. 把多个属性存在一个映射(map)中,而不是每个存在单独的字段中

 

Kotlin中的属性代理语法定义如下:

val/var <property name>: <Type> by <expression>

expression就是代理,属性property的get() 和 set()方法会代理给expression的getValue() 和 setValue()方法,属性代理不需要实现接口。

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

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
 
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

//测试
val e = Example()
println(e.p)

//输出
Example@33a17727, thank you for delegating ‘p’ to me!

 

Kotlin标准库通过工厂方法提供了一些有用的代理,包括lazy() 、observable()、voteable()、notnull()

1. 懒加载属性代理 lazy properties

懒加载属性在第一次调用到时会计算其值,并保存下来,下此调用时直接返回保存的值。

lazy()函数接受一个lambda表达式,返回一个Lazy<T>的实例对象,该对象用以代理一个懒加载属性。lazy()函数接受的ambda表达式的值就是其属性的计算值。

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main(args: Array<String>) {
    println(lazyValue)
    println(lazyValue)
}

//输出
computed!
Hello
Hello

lazy()函数可以接收一个LazyThreadSafetyMode参数,默认情况下,对lazy属性的求值是同步的(synchronized),即LazyThreadSafetyMode.SYNCHRONIZED , 如果多个线程可以同时计算属性值,可以使用LazyThreadSafetyMode.PUBLICATION,

如果属性的初始化是确定在一个线程里,可以使用LazyThreadSafetyMode.NONE来提高性能,因为省去了保证线程安全的开销。

 

2. 可观察属性代理 Delegates.observable()

Delegates.observable()有两个参数,一个初始值,一个修改后的操作,每次值的改变都会调用该操作

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun main(args: Array<String>) {
    val user = User()
    user.name = "first"
    user.name = "second"
}

//输出
<no name> -> first
first -> second

3. 可否决属性代理 Delegates.voteable()

当把属性代理给Delegates.voteable()这个函数时,可以通过onChange函数返回值是否为true,来选择属性的值是否需要改变。

   var name: String by Delegates.vetoable("<no name>") {
        prop, old, new ->
       true  //  或者false
    }

4. 非空属性代理 Delegates.notNull()

//将属性name限制为非空,如果赋值为null,编译器报错
var name: String by Delegates.notNull()

5.  属性代理给Map映射

在程序中,解析json或者做一些其他动态的事情时,可以使用该方法,将map对象本身当作属性的代理

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

val user = User(mutableMapOf(
        "name" to "John Doe",
        "age"  to 25
))

fun main(args: Array<String>) {
    println(user.name) // Prints "John Doe"
    println(user.age) // Prints 25
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值