所谓的委托就是将一个类的
方法
和对象
交给另外一个类的对象就行处理
比如简单的实现自己的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
}
}
使用一个其他对象来完成类属性的读和写。
委托类必须实现的方法是,val
属性必须实现的是getValue
,var
也必须同时实现和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]);
}
为了方便使用委托,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
}
}