Kotlin委托的使用和原理

Kotlin委托的使用和原理

什么是委托

委托就是一种通过将实际工作交给其他对象来实现的设计模式;kotlin给我们提供了by关键词实现委托.

类委托

首先来看类委托,类委托的意思就是A中持有一个B的实例,A实现某个功能都交给B来实际执行.我们来看代码:

kotlin 复制代码
interface IVehicle {
    fun drive():String
}
​
class Car(private val vehicle: IVehicle) : IVehicle by vehicle
​
fun main(){
    val car = Car(object :IVehicle{
        override fun drive(): String {
            return "drive car"
        }
    })
    println(car.drive())
}

Car类实现了IVehicle接口及持有了一个IVehicle实例,并通过by关键词将逻辑委托给vehicle.反编译成java代码看下:

kotlin 复制代码
public final class Car implements IVehicle {
   private final IVehicle vehicle;
​
   public Car(@NotNull IVehicle vehicle) {
      Intrinsics.checkNotNullParameter(vehicle, "vehicle");
      super();
      this.vehicle = vehicle;
   }
​
   @NotNull
   public String drive() {
      return this.vehicle.drive();
   }
}

Car这个类实现了IVehicle,且通过by属性委托,编译器自动生成了drive()接口方法的实现,并调用构造方法中传入的委托对象的drive()方法.

属性委托

属性委托就是指一个类实现了ReadWriteProperty接口,同时把一个属性的get和set方法委托给这个委托类.我们来看代码:

kotlin 复制代码
class PropertyDelegate: ReadWriteProperty<Any?, Int> {
    var v = 0
    override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        println("getValue")
        return v
    }
​
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
        println("setValue")
        v = value * value
    }
}
​
fun main(){
    var propertyValue :Int by PropertyDelegate()
    propertyValue = 10
    println(propertyValue)
}

这段代码中首先声明了一个委托类,实现了setValue和getValue两个方法,实际上这两个方法都是运算符重载方法,以getValue为例,它其实是这个方法:

kotlin 复制代码
/**
 * Returns the value of the property for the given object.
 * @param thisRef the object for which the value is requested.
 * @param property the metadata for the property.
 * @return the property value.
 */
public override operator fun getValue(thisRef: T, property: KProperty<*>): V

在main方法中通过by关键字把value委托给委托类实例,只要对value赋值或获取value时,就会调用到委托类的getValue和setValue方法.

我们看下反编译后的代码:

typescript 复制代码
public final class PropertyDelegate implements ReadWriteProperty {
   private int v;
​
   public final int getV() {
      return this.v;
   }
​
   public final void setV(int var1) {
      this.v = var1;
   }
​
   @NotNull
   public Integer getValue(@Nullable Object thisRef, @NotNull KProperty property) {
      Intrinsics.checkNotNullParameter(property, "property");
      String var3 = "getValue";
      System.out.println(var3);
      return this.v;
   }
​
   // $FF: synthetic method
   // $FF: bridge method
   public Object getValue(Object var1, KProperty var2) {
      return this.getValue(var1, var2);
   }
​
   public void setValue(@Nullable Object thisRef, @NotNull KProperty property, int value) {
      Intrinsics.checkNotNullParameter(property, "property");
      String var4 = "setValue";
      System.out.println(var4);
      this.v = value * value;
   }
​
   // $FF: synthetic method
   // $FF: bridge method
   public void setValue(Object var1, KProperty var2, Object var3) {
      this.setValue(var1, var2, ((Number)var3).intValue());
   }
}
​
public final class PropertyDelegateKt {
   // $FF: synthetic field
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(PropertyDelegateKt.class, "propertyValue", "<v#0>", 1))};
​
   public static final void main() {
      PropertyDelegate var10000 = new PropertyDelegate();
      KProperty var1 = $$delegatedProperties[0];
      PropertyDelegate propertyValue = var10000;
      propertyValue.setValue((Object)null, var1, 10);
      int var2 = propertyValue.getValue((Object)null, var1);
      System.out.println(var2);
   }
​
   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
​
​

在main方法中,生成了一个PropertyDelegate代理类,当对propertyValue赋值时就会调用代理类的setValue方法,当获取propertyValue值的时候就调用代理类的getValue方法.

属性委托还有一种用法,看一下代码

kotlin 复制代码
fun main(){
    val map:MutableMap<String,String> = mutableMapOf()
    map["name"] = "name1"
​
    var name by map
    println(name)
    name = "name2"
}

当访问/修改name时,就会从map中获取key为name的value值并返回,看下反编译后的代码:

arduino 复制代码
public final class MapDelegateKt {
   // $FF: synthetic field
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(MapDelegateKt.class, "name", "<v#0>", 1))};
​
   public static final void main() {
      Map map = (Map)(new LinkedHashMap());
      map.put("name", "name1");
      KProperty var2 = $$delegatedProperties[0];
      Object var4 = null;
      Object var3 = MapsKt.getOrImplicitDefaultNullable(map, var2.getName());
      System.out.println(var3);
      var4 = null;
      String var5 = "name2";
      map.put(var2.getName(), var5);
   }
​
   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
  1. 通过反射生成了一个KProperty类型对象变量$$delegatedProperties,通过这个对象的getName()我们就能拿到变量名称,比如这里的"name"变量名;
  2. 最终调用了MapsKt.getOrImplicitDefaultNullable方法,去map散列表去查找"name"这个key对应的value;

Kotlin提供的属性委托

  1. 延迟属性Lazy

    kotlin 复制代码
    val count : Int by lazy{
        println("init")
        0
    }

    lazy() 接受一个lambda表达式并返回一个Lazy实例的函数,只有当第一次调用count时,count变量才会初始化,也就是调用lambda表达式.lazy()的实现是一个SynchronizedLazyImpl()实例

    kotlin 复制代码
    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)
    }
  2. 可观察属性Observable

    kotlin 复制代码
    var age : Int by Delegates.observable(0) {
            _, oldValue, newValue ->
        println("old value : $oldValue, new value : $newValue")
        newValue > oldValue
    }

    Delegates.observable()接受两个参数,一个是初始值,一个是修改时的lambda表达式:

    kotlin 复制代码
    public abstract class ObservableProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> {
        private var value = initialValue
    
        /**
         *  The callback which is called before a change to the property value is attempted.
         *  The value of the property hasn't been changed yet, when this callback is invoked.
         *  If the callback returns `true` the value of the property is being set to the new value,
         *  and if the callback returns `false` the new value is discarded and the property remains its old value.
         */
        protected open fun beforeChange(property: KProperty<*>, oldValue: V, newValue: V): Boolean = true
    
        /**
         * The callback which is called after the change of the property is made. The value of the property
         * has already been changed when this callback is invoked.
         */
        protected open fun afterChange(property: KProperty<*>, oldValue: V, newValue: V): Unit {}
    
        public override fun getValue(thisRef: Any?, property: KProperty<*>): V {
            return value
        }
    
        public override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
            val oldValue = this.value
            if (!beforeChange(property, oldValue, value)) {
                return
            }
            this.value = value
            afterChange(property, oldValue, value)
        }
    }
相关推荐
老蒋每日coding5 小时前
AI Agent 设计模式系列(十九)—— 评估和监控模式
人工智能·设计模式
会员果汁6 小时前
23.设计模式-解释器模式
设计模式·解释器模式
zfoo-framework11 小时前
kotlin
android·开发语言·kotlin
「QT(C++)开发工程师」13 小时前
C++设计模式
开发语言·c++·设计模式
茶本无香14 小时前
设计模式之七—装饰模式(Decorator Pattern)
java·设计模式·装饰器模式
漂洋过海的鱼儿1 天前
设计模式——EIT构型(三)
java·网络·设计模式
老蒋每日coding1 天前
AI Agent 设计模式系列(十八)—— 安全模式
人工智能·安全·设计模式
老蒋每日coding1 天前
AI Agent 设计模式系列(十六)—— 资源感知优化设计模式
人工智能·设计模式·langchain
老蒋每日coding1 天前
AI Agent 设计模式系列(十七)—— 推理设计模式
人工智能·设计模式
冷崖1 天前
桥模式-结构型
c++·设计模式