• Kotlin 之代理 Delegate


    代理关键字 by

    属性代理:对象X代替属性a实现getter、setter方法。

    接口代理:对象X代替类B实现接口C的方法。

    举例

    属性代理

    在UI初始中使用过,代码如下:

     1 class MainActivity : AppCompatActivity() {
     2 
     3     private val mTvName: TextView by lazy {
     4         findViewById(R.id.name)
     5     }
     6 
     7     override fun onCreate(savedInstanceState: Bundle?) {
     8         super.onCreate(savedInstanceState)
     9         setContentView(R.layout.activity_main)
    10     }
    11 }

    接口lazy的实例代理了对象MainActivity实例的属性mTvName的getter方法。

    lazy是一个Lambda函数,lazy实现:

      1 /**
      2  * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
      3  * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
      4  *
      5  * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
      6  *
      7  * Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
      8  * the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
      9  */
     10 public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
     11 
     12 /**
     13  * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
     14  * and thread-safety [mode].
     15  *
     16  * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
     17  *
     18  * Note that when the [LazyThreadSafetyMode.SYNCHRONIZED] mode is specified the returned instance uses itself
     19  * to synchronize on. Do not synchronize from external code on the returned instance as it may cause accidental deadlock.
     20  * Also this behavior can be changed in the future.
     21  */
     22 public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
     23     when (mode) {
     24         LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
     25         LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
     26         LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
     27     }
     28 
     29 /**
     30  * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
     31  * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
     32  *
     33  * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
     34  *
     35  * The returned instance uses the specified [lock] object to synchronize on.
     36  * When the [lock] is not specified the instance uses itself to synchronize on,
     37  * in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock.
     38  * Also this behavior can be changed in the future.
     39  */
     40 public actual fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer, lock)
     41 
     42 
     43 
     44 private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
     45     private var initializer: (() -> T)? = initializer
     46     @Volatile private var _value: Any? = UNINITIALIZED_VALUE
     47     // final field is required to enable safe publication of constructed instance
     48     private val lock = lock ?: this
     49 
     50     override val value: T
     51         get() {
     52             val _v1 = _value
     53             if (_v1 !== UNINITIALIZED_VALUE) {
     54                 @Suppress("UNCHECKED_CAST")
     55                 return _v1 as T
     56             }
     57 
     58             return synchronized(lock) {
     59                 val _v2 = _value
     60                 if (_v2 !== UNINITIALIZED_VALUE) {
     61                     @Suppress("UNCHECKED_CAST") (_v2 as T)
     62                 } else {
     63                     val typedValue = initializer!!()
     64                     _value = typedValue
     65                     initializer = null
     66                     typedValue
     67                 }
     68             }
     69         }
     70 
     71     override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
     72 
     73     override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
     74 
     75     private fun writeReplace(): Any = InitializedLazyImpl(value)
     76 }
     77 
     78 
     79 private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
     80     @Volatile private var initializer: (() -> T)? = initializer
     81     @Volatile private var _value: Any? = UNINITIALIZED_VALUE
     82     // this final field is required to enable safe initialization of the constructed instance
     83     private val final: Any = UNINITIALIZED_VALUE
     84 
     85     override val value: T
     86         get() {
     87             val value = _value
     88             if (value !== UNINITIALIZED_VALUE) {
     89                 @Suppress("UNCHECKED_CAST")
     90                 return value as T
     91             }
     92 
     93             val initializerValue = initializer
     94             // if we see null in initializer here, it means that the value is already set by another thread
     95             if (initializerValue != null) {
     96                 val newValue = initializerValue()
     97                 if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
     98                     initializer = null
     99                     return newValue
    100                 }
    101             }
    102             @Suppress("UNCHECKED_CAST")
    103             return _value as T
    104         }
    105 
    106     override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
    107 
    108     override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
    109 
    110     private fun writeReplace(): Any = InitializedLazyImpl(value)
    111 
    112     companion object {
    113         private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
    114             SafePublicationLazyImpl::class.java,
    115             Any::class.java,
    116             "_value"
    117         )
    118     }
    119 }

    当然能代理getter方法就能代理setter方法,上代码:

    class Person() {
    
        private var mName: String by Delegates.observable("") {
            property, oldValue, newValue ->
            println("name setter old value: $oldValue to new value: $newValue")
        }
        
    }

    源码实现:

     1 /**
     2  * Standard property delegates.
     3  */
     4 public object Delegates {
     5     /**
     6      * Returns a property delegate for a read/write property with a non-`null` value that is initialized not during
     7      * object construction time but at a later time. Trying to read the property before the initial value has been
     8      * assigned results in an exception.
     9      *
    10      * @sample samples.properties.Delegates.notNullDelegate
    11      */
    12     public fun <T : Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
    13 
    14     /**
    15      * Returns a property delegate for a read/write property that calls a specified callback function when changed.
    16      * @param initialValue the initial value of the property.
    17      * @param onChange the callback which is called after the change of the property is made. The value of the property
    18      *  has already been changed when this callback is invoked.
    19      *
    20      *  @sample samples.properties.Delegates.observableDelegate
    21      */
    22     public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
    23             ReadWriteProperty<Any?, T> =
    24         object : ObservableProperty<T>(initialValue) {
    25             override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
    26         }
    27 
    28     /**
    29      * Returns a property delegate for a read/write property that calls a specified callback function when changed,
    30      * allowing the callback to veto the modification.
    31      * @param initialValue the initial value of the property.
    32      * @param onChange the callback which is called before a change to the property value is attempted.
    33      *  The value of the property hasn't been changed yet, when this callback is invoked.
    34      *  If the callback returns `true` the value of the property is being set to the new value,
    35      *  and if the callback returns `false` the new value is discarded and the property remains its old value.
    36      *
    37      *  @sample samples.properties.Delegates.vetoableDelegate
    38      *  @sample samples.properties.Delegates.throwVetoableDelegate
    39      */
    40     public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
    41             ReadWriteProperty<Any?, T> =
    42         object : ObservableProperty<T>(initialValue) {
    43             override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
    44         }
    45 
    46 }

     属性代理最重要的接口类源码:

     1 /**
     2  * Base interface that can be used for implementing property delegates of read-write properties.
     3  *
     4  * This is provided only for convenience; you don't have to extend this interface
     5  * as long as your property delegate has methods with the same signatures.
     6  *
     7  * @param R the type of object which owns the delegated property.
     8  * @param T the type of the property value.
     9  */
    10 public interface ReadWriteProperty<in R, T> {
    11     /**
    12      * Returns the value of the property for the given object.
    13      * @param thisRef the object for which the value is requested.
    14      * @param property the metadata for the property.
    15      * @return the property value.
    16      */
    17     public operator fun getValue(thisRef: R, property: KProperty<*>): T
    18 
    19     /**
    20      * Sets the value of the property for the given object.
    21      * @param thisRef the object for which the value is requested.
    22      * @param property the metadata for the property.
    23      * @param value the value to set.
    24      */
    25     public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
    26 }

    其实,我们也可以实现类似接口,通过operator操作符:

     1 class Foo() {
     2     val x: Int by Person()
     3 
     4     var y: Int by Person()
     5 }
     6 
     7 class Person() {
     8 
     9     private var value: Int? = null
    10 
    11     operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
    12         return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
    13     }
    14 
    15     operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
    16         this.value = value
    17     }
    18 
    19 }

    接口代理

    未使用代理 by :

     1 interface IApi {
     2     fun methodA()
     3     fun methodB()
     4     fun methodC()
     5 }
     6 
     7 class Person(private val api: IApi): IApi {
     8     
     9     override fun methodA() {
    10         api.methodA()
    11     }
    12 
    13     override fun methodB() {
    14         api.methodB()
    15     }
    16 
    17     override fun methodC() {
    18         api.methodC()
    19     }
    20 
    21 }

    使用代理 by :

     1 interface IApi {
     2     fun methodA()
     3     fun methodB()
     4     fun methodC()
     5 }
     6 
     7 class Person(private val api: IApi) : IApi by api {
     8     // 对象api代替类Person实现接口IApi方法
     9     override fun methodC() {
    10         TODO("Not yet implemented")
    11     }
    12 }
  • 相关阅读:
    Quartz实现动态定时任务
    Springboot跨域和SpringCloud跨域
    java8 LocalDate 判断一年中的标准周末和工作日
    [WIP]iOS/macOS开发中常见的宏解释
    [WIP] Objective-C Runtime调试
    [WIP] iOS课程作业
    macOS 允许任何来源的应用
    Win10系统下移动、复制、删除文件需要管理员权限的解决方法
    flutter MediaQuery获取屏幕宽度高度密度通知栏高度等屏幕信息
    Flutter 获取状态栏高度、appBar高度 和 手机屏幕宽高
  • 原文地址:https://www.cnblogs.com/naray/p/12992952.html
Copyright © 2020-2023  润新知