kotlin代理模式就是这么简单
我们都熟悉代理模式,就是把自己要做的事情委托给另外一个对象,这个对象就代理对象,java的代理模式包括静态代理以及动态代理,在这里就不过多赘述了,今天我们来说一说kotlin的代理。
kotlin中可以零样板代码地原生支持它,kotlin中包括,类代理,以及属性代理
类代理
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() // 输出 10
}
可以看到kotlin实现类代理非常简单,通过关键字by就可以让b代理自己的方法,b将会在Derived中内部存储,并且编译器将生成转发给b的所有 Base的方法。
属性代理
谈到属性代理,我们用到的较多的有lazy、Delegates.notNull()、Delegates.observable()等,这些都是kotlin自带的一些标准代理,那我们自己来写一个属性代理
class Example {
val p: String by Delegate()
}
class Delegate {
}
如果我们直接这样写的话,会发现Delegate下面会有错误提示, miss 'getValue(mainActivity: MainActivity, property: KProperty<*>): Any' method on delegate of type 'Delegate' 这个提示的意思是说需要提供一个getValue的方法,如果我们把p前面改成var,那么编译器又会提示一个需要setValue方法。
class Example {
var p: String by Delegate()
}
class Delegate {
private var mRealValue = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return mRealValue
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
mRealValue = value
}
}
其实属性的代理,就是把自己的属性对应的get()和set()会被代理给它的getValue()和setValue()方法。两函数都需要用 operator 关键字来进行标记,代理类可以实现包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一,这俩接口是在 Kotlin 标准库中声明的。
在每个代理属性的实现的背后,Kotlin 编译器都会生成辅助属性并代理给它。例如,对于属性 prop,生成隐藏属性 prop$delegate,而访问器的代码只是简单地代理给这个附加属性:
class C {
var prop: Type by MyDelegate()
}
// 这段是由编译器生成的相应代码:
class C {
private val prop$delegate = MyDelegate()
var prop: Type
get() = prop$delegate.getValue(this, this::prop)
set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
Kotlin 编译器在参数中提供了关于 prop 的所有必要信息:第一个参数 this 引用到外部类C的实例而this::prop是KProperty类型的反射象,该对象描述prop自身。 我们继续分析一下lazy方法,自己写一个lazy的属性
class Demo1 {
private val a by lazy { 1 }
}
使用kotlin bytecode工具查看字节码,再进行反编译
public final class Demo1 {
// $FF: synthetic field
static final KProperty[] ?delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Demo1.class), "a", "getA()I"))};
private final Lazy a$delegate;
private final int getA() {
Lazy var1 = this.a$delegate;
KProperty var3 = ?delegatedProperties[0];
return ((Number)var1.getValue()).intValue();
}
public Demo1() {
this.a$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
}
编译器为我们生成了一个a$delegate的Lazy,以及?delegatedProperties的KProperty[]对象,还有一个getA的方法,并且在构造里面通过 LazyKt.lazy((Function0)null.INSTANCE)初始化了a$delegate,这个方法其实就是我们的lazy()方法,我们继续看lazy方法
public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
}
else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
在 SynchronizedLazyImpl 实现代码里,通过 _value 用来真正保存属性的值。_value 的默认值是 UNINITIALIZED_VALUE (一个自定义的对象)。当 _value 不是默认值的时候,就会直接把 _value 的值作为 getValue() 的返回;当 _value 还是默认值的时候,就会调用 initializer 初始化表达式完成初始化,赋值给 _value 并作为 getValue() 的返回
所以我们再获取a的值时会去先调用getA()方法,回去调用Lazy的getValue方法,然后就会走SynchronizedLazyImpl的懒属性的逻辑,整个lazy的流程就是这样。