委托

简单委托

如果把接口抽象类理解为是方法抽象层面一致性委托则可以认为是解决了方法实现层面一致性。更直接的,它本质上是允许我们在实现层面上进行复用。

本应由c属性实现的方法的委托给已经实现接口的a属性b属性

interface A {
    fun a()
}

interface B {
    fun b()
}

var a = object : A {
    override fun a() {
        println("a function delegated by  ${this}")
    }
}
var b = object : B {
    override fun b() {
        println("b function delegated by  ${this}")
    }
}

fun main(args: Array) {

    var c = object : A by a, B by b{ } 
    c.a() //打印 "a function delegated by  doulala.kotlin.demo.delegation.DelegationKt$a"
    c.b() //打印 "b function delegated by  doulala.kotlin.demo.delegation.DelegationKt$b"
}

实验1:如果只想委托部分方法,关键方法自己实现。

var d = object : all {     
    override fun a() {
        //donothing
        println("d.a function do nothing")  
    }

    override fun b() {
        println("d.b function delegated by  ${this}")
    }
}

fun main(args: Array) {

    var c = object : all by d {
        override fun a() {  //override d实例的 a()方法
            println("c.a function override d.a function")
        }
    }
    c.b()  //委托给d.b(), 输出"d.b function delegated by  doulala.kotlin.demo.delegation.DelegationKt$d"
    c.a()  //最终将调用 c.a()方法,输出"c.a function override d.a function"
}


实验2,如果同时继承多个接口,接口方法名一样,会先调用哪个? 会报错

interface A {
    fun a()
    fun samename()
}

interface B {
    fun b()
    fun samename()
}

var a = object : A {
    override fun samename() {
        println("samename function in a")
    }

    override fun a() {
        println("a function ")
    }
}
var b = object : B {
    override fun samename() {
        println("samename function in b")
    }

    override fun b() {
        println("b function ")
    }
}

fun main(args: Array) {

    var c = object : A by a, B by b{} //会报错,被提示实现了多次
    c.a()
    c.b()
    c.samename()
    
}

  1. 委托(Delegation)的关键词是 by
  2. 委托可以通过重写方法控制委托的范围
  3. 委托时会严格校验被委托的方法来源,如果出现了相同的方法,会报错(这里与继承的判断是有区别的) 。限制就是安全所在。

属性委托

系统为我们提供了一些常用的属性委托,包括:

  • 延迟属性(lazy properties): 其值只在首次访问时计算;
  • 可观察属性(observable properties): 监听器会收到有关此属性变更的通知;
  • 把多个属性储存在一个映射map中,而不是每个存在单独的字段中。

延迟属性 lazy()

  1. lazy属性主要提供了只读属性——通过计算后设置属性值的能力

  2. 他提供了三种模式处理线程安全,包括 -

  • 用于多线程间需要同步的LazyThreadSafetyMode.SYNCHRONIZED
  • 如存在多线程使用,但是无需同步的LazyThreadSafetyMode.PUBLICATION -
  • 单线程场景的的LazyThreadSafetyMode.NONE
fun main(args: Array) {
    val p: String by lazy(LazyThreadSafetyMode.NONE) {
        println("get() progress")
        "value"  //lazy其实是重写了get()方法,最后一行是p的值
    }
}

我们看一下他的源码,发现Lazy的核心就是重写属性的get()方法:

public fun  lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy =
        when (mode) {
            LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
            LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
            LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
        }

//最简单的是UnsafeLazyImpl,单线程模式
internal class UnsafeLazyImpl(initializer: () -> T) : Lazy, Serializable {
    private var initializer: (() -> T)? = initializer  //拿到初始化的lambda方法
    private var _value: Any? = UNINITIALIZED_VALUE //定义了一个非法值

    override val value: T
        get() {         //这行应该和上面一行连起来看,就是重写该属性的get()方法
            if (_value === UNINITIALIZED_VALUE) {
                _value = initializer!!() //初始化
                initializer = null
            }
            @Suppress("UNCHECKED_CAST")
            return _value as T //返回初始化后的值
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE // 这个是Lazy的方法,用于记录是否初始化结束。

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."  //重写toString方法

    private fun writeReplace(): Any = InitializedLazyImpl(value) //未找到方法作用
}


可观察属性 Observable

Delegates一共提供两个代理工厂observablevetoable 方法

observable委托对象可以对数值的变化进行监控。共需要提供两个参数

  1. 参数A:initialValue: T 用于设置初始值
  2. 参数B:(property: KProperty<*>, oldValue: T, newValue: T) -> Unit 监控并获取对象引用变更前数据变更后数据
var name: String by Delegates.observable("init") { prop, old, new ->
    println("old : $old")
    println("new : $new")
}

fun main(args: Array) {
    name = "123"
    name = "456"
}

vetoable委托对象可以对数值的变化进行控制。与observable唯一的不同是,参数B的返回值变为了Boolean,如果返回值为true接受变化,如果为false不接受变化。

var age: Int by Delegates.vetoable(18) { prop, old, new ->
    println("old : $old")
    println("new : $new")
    val accept=new>16
    println("accept : $accept")
    accept //只接受>16的变更
}


fun main(args: Array) {
    age = 12
    println("age =$age") //输出: "age =18"
    age = 20
    println("age =$age")//输出: "age =20"
}

解密属性委托

属性委托的原理是by了一个对象,这个对象其实是委托了getValuesetValue方法:


interface ReadOnlyProperty {  //只读的Delegate
   operator fun getValue(thisRef: R, property: KProperty<*>): T
}


interface ReadWriteProperty {//读写的Delegate
   operator fun getValue(thisRef: R, property: KProperty<*>): T
   operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

一个自定义的属性委托:

fun main(args: Array) {

    var a: String by object : ReadWriteProperty {
        var _value: String = "" //属性委托一般都需要一个间接对象进行数据读取与赋值
        
        override fun getValue(thisRef: Any?, property: KProperty<*>): String {
         
            print("in getValue")
            print("$thisRef")
            print("$property")
            return _value
        }
        override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {

            println("in setValue")
            _value = value
        }
    }
    a="1213"  //输出 “in setValue”
    println(a) //输出 in getValue null var a: kotlin.String  1213

}


你可能感兴趣的:(委托)