Kotlin委托

1. What is Delegate

所谓的委托就是将一个类的方法对象交给另外一个类的对象就行处理

1.1 类委托

比如简单的实现自己的Set类,该集合类的方法可以交由其他类对象的方法进行处理。如下就是一种简单的代理。

class TestSetDelegate<T>(private val hashSet: HashSet<T>): Set<T> {
    override val size: Int
        get() = hashSet.size

    override fun isEmpty(): Boolean = hashSet.isEmpty()

    override fun iterator(): Iterator<T> = hashSet.iterator()

    override fun containsAll(elements: Collection<T>): Boolean = hashSet.containsAll(elements)

    override fun contains(element: T): Boolean = hashSet.contains(element)
}

但是这里存在一个问题,如果基类需要实现的方法很多,那将非常麻烦。Kotlin提供了简单的委托方式如下。

class TestSetDelegate<T>(private val hashSet: HashSet<T>): Set<T> by hashSet {
 
}

这种方法等价于上面的实现,另外我们还可以重写某些方法。

class TestSetDelegate<T>(private val hashSet: HashSet<T>): Set<T> by hashSet {

    override fun contains(element: T): Boolean {
        if (element == null) {
            return false
        }
        return true
    }
}

1.2 属性委托

使用一个其他对象来完成类属性的读和写。

委托类必须实现的方法是,val属性必须实现的是getValuevar也必须同时实现和setValue

    operator fun getValue(
        /**
         *  属性的拥有者对象类型, 可以声明为泛型
         */
        clz: Test,
        /**
         * Kotlin中的一个属性操作类,可用于获取各种属性相关的值,
         * 在当前场景下用不着,但是必须在方法参数上进行声明
         */
        property: KProperty<*>
    ): Int { // 需要委托的属性类型
        return clz.string.length
    }

    operator fun setValue(
        clz: Test,
        property: KProperty<*>,
        /**
         * 需要设置的值
         */
        i: Int
    ) {

    }

如下将Test类的length属性的值交给DelegateTest类实现。

import kotlin.reflect.KProperty

class Test(val string: String) {
    val length: Int by DelegateTest()
}

class DelegateTest {
    operator fun getValue(clz: Test, property: KProperty<*>): Int {
        return clz.string.length
    }
}

编译成Java字节码如下:

public final class Test {
   // $FF: synthetic field
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Test.class, "length", "getLength()I", 0))};
   @NotNull
   private final DelegateTest length$delegate;
   @NotNull
   private final String string;

   public final int getLength() {
      return this.length$delegate.getValue(this, $$delegatedProperties[0]);
   }

   @NotNull
   public final String getString() {
      return this.string;
   }

   public Test(@NotNull String string) {
      Intrinsics.checkNotNullParameter(string, "string");
      super();
      this.string = string;
      this.length$delegate = new DelegateTest();
   }
}

public final class DelegateTest {
   public final int getValue(@NotNull Test clz, @NotNull KProperty property) {
      Intrinsics.checkNotNullParameter(clz, "clz");
      Intrinsics.checkNotNullParameter(property, "property");
      return clz.getString().length();
   }
}

可以看到会生成一个委托类对象,获取值的时候传入对象相关。

   public final int getLength() {
      return this.length$delegate.getValue(this, $$delegatedProperties[0]);
   }

1.3 接口实现

为了方便使用委托,kotlin提供了两个接口。可读接口和读写接口。直接实现接口即可

/**
 * Base interface that can be used for implementing property delegates of read-only properties.
 *
 * This is provided only for convenience; you don't have to extend this interface
 * as long as your property delegate has methods with the same signatures.
 *
 * @param T the type of object which owns the delegated property.
 * @param V the type of the property value.
 */
public fun interface ReadOnlyProperty<in T, out V> {
    /**
     * 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 operator fun getValue(thisRef: T, property: KProperty<*>): V
}

/**
 * Base interface that can be used for implementing property delegates of read-write properties.
 *
 * This is provided only for convenience; you don't have to extend this interface
 * as long as your property delegate has methods with the same signatures.
 *
 * @param T the type of object which owns the delegated property.
 * @param V the type of the property value.
 */
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
    /**
     * 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

    /**
     * Sets 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.
     * @param value the value to set.
     */
    public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

class Test(val string: String) {
    val length: Int by DelegateTest()
}

class DelegateTest: ReadOnlyProperty<Test, Int> {
    override fun getValue(thisRef: Test, property: KProperty<*>): Int {
        return thisRef.string.length
    }
}

你可能感兴趣的:(kotlin,android,java)