Kotlin基础(10)-代理模式在kotlin中的使用

前言 本文简要介绍代理模式在kotlin中的使用
手写一个代理模式 定义一个接口中定义行走方法,并在坦克类中实现行走方法,而行走的具体方法则由实现了行走方法的代理类实现。代码如下

interface Moveable { fun move(); }class MoveProxy : Moveable { override fun move() { Log.e("move", "MoveProxy Moving") }}class Tank : Moveable { var proxy: MoveProxy; override fun move() { proxy.move() }constructor(proxy: MoveProxy) { this.proxy = proxy; }}val tank:Tank= Tank(MoveProxy()) tank.move()

测试结果
11-11 16:59:43.100 16068-16068/com.zhqy.javademo E/move: MoveProxy Moving

而我们也可以通过Kotlin中定义好的关键字by来实现上述功能
方法静态代理的实现
interface Moveable { fun move(); }class MoveProxy : Moveable { override fun move() { Log.e("move", "MoveProxy Moving") }}class Tank : Moveable by MoveProxy() {}

测试结果
11-11 17:07:04.669 16274-16274/? E/move: MoveProxy Moving

从测试结果上来我们获得了一样的结果,这是为什么呢
public final class Tank implements Moveable { // $FF: synthetic field private final MoveProxy $$delegate_0 = new MoveProxy(); public void move() { this.$$delegate_0.move(); } }

从Java字节码中可以看了只要通过关键字By声明我们实例化的一个代理类,余下的工作都由kotlin来为我们实现。kotlin不仅仅能实现方法的静态代理也能够实现属性的静态代理
属性静态代理的实现
下面一个例子实现对属性name的获取数据和设置数据时打印相关的数据
class Person(){ var name:String by MyDelegate() } //代理类 class MyDelegate{ //获取属性值的方法 /** * person 实例对象 * property 属性集合(包含修饰符,名称等) */ operator fun getValue(person: Person, property: KProperty<*>): String {Log.e("getValue","$person:${property.name}") return "" }/** * person 实例对象 * property 属性集合(包含修饰符,名称等) * s:设置的值 */ //设置属性值的方法 operator fun setValue(person: Person, property: KProperty<*>, s: String) { Log.e("getValue","$person:${property.name}:$s") TODO("not implemented") //To change body of created functions use File | Settings | File Templates. }}var person=Person(); person.name="张三" person.name

测是结果
11-11 17:23:24.271 17635-17635/? E/setValue: com.zhqy.javademo.Person@3157fe3:name:张三 11-11 17:23:24.271 17635-17635/? E/getValue: com.zhqy.javademo.Person@3157fe3:name

需要注意的是代理类需要实现以下两个方法
/** * person 实例对象 * property 属性集合(包含修饰符,名称等) */ operator fun getValue(person: Person, property: KProperty<*>): String {Log.e("getValue","$person:${property.name}") return "" }/** * person 实例对象 * property 属性集合(包含修饰符,名称等) * s:设置的值 */ //设置属性值的方法 operator fun setValue(person: Person, property: KProperty<*>, s: String) { Log.e("setValue","$person:${property.name}:$s") }

【Kotlin基础(10)-代理模式在kotlin中的使用】Java字节码如下
public final class Person { // $FF: synthetic field static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person.class), "name", "getName()Ljava/lang/String; "))}; @NotNull private final MyDelegate name$delegate = new MyDelegate(); @NotNull public final String getName() { return this.name$delegate.getValue(this, $$delegatedProperties[0]); }public final void setName(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, ""); this.name$delegate.setValue(this, $$delegatedProperties[0], var1); } }

从字节码中可以看到声明了代理类MyDelegate的一个对象,并在get和set方法中分别调用了getVale和setValue方法实现代理功能。
当然也可以使用关键字
class Person(){ var name:String by Delegate() }class Delegate(){operatorfun provideDelegate(person: Person, property: KProperty<*>):MyDelegate{ return MyDelegate() } }//代理类 class MyDelegate{ //获取属性值的方法 /** * person 实例对象 * property 属性集合(包含修饰符,名称等) */ operator fun getValue(person: Person, property: KProperty<*>): String {Log.e("getValue","$person:${property.name}") return "" }/** * person 实例对象 * property 属性集合(包含修饰符,名称等) * s:设置的值 */ //设置属性值的方法 operator fun setValue(person: Person, property: KProperty<*>, s: String) { Log.e("setValue","$person:${property.name}:$s") }}

字节码如下
// Person.java package com.zhqy.javademo; import kotlin.Metadata; import kotlin.jvm.internal.Intrinsics; import kotlin.jvm.internal.MutablePropertyReference1Impl; import kotlin.jvm.internal.Reflection; import kotlin.reflect.KProperty; import org.jetbrains.annotations.NotNull; @Metadata( mv = {1, 1, 10}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\b\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002R+\u0010\u0005\u001a\u00020\u00042\u0006\u0010\u0003\u001a\u00020\u00048F@FX\u0086\u008e\u0002¢\u0006\u0012\n\u0004\b\n\u0010\u000b\u001a\u0004\b\u0006\u0010\u0007\"\u0004\b\b\u0010\t¨\u0006\f"}, d2 = {"Lcom/zhqy/javademo/Person; ", "", "()V", "", "", "name", "getName", "()Ljava/lang/String; ", "setName", "(Ljava/lang/String; )V", "name$delegate", "Lcom/zhqy/javademo/MyDelegate; ", "production sources for module app"} ) public final class Person { // $FF: synthetic field static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person.class), "name", "getName()Ljava/lang/String; "))}; @NotNull private final MyDelegate name$delegate; @NotNull public final String getName() { return this.name$delegate.getValue(this, $$delegatedProperties[0]); }public final void setName(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, ""); this.name$delegate.setValue(this, $$delegatedProperties[0], var1); }public Person() { this.name$delegate = (new Delegate()).provideDelegate(this, $$delegatedProperties[0]); } } // Delegate.java package com.zhqy.javademo; import kotlin.Metadata; import kotlin.jvm.internal.Intrinsics; import kotlin.reflect.KProperty; import org.jetbrains.annotations.NotNull; @Metadata( mv = {1, 1, 10}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001d\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00062\n\u0010\u0007\u001a\u0006\u0012\u0002\b\u00030\bH\u0086\u0002¨\u0006\t"}, d2 = {"Lcom/zhqy/javademo/Delegate; ", "", "()V", "provideDelegate", "Lcom/zhqy/javademo/MyDelegate; ", "person", "Lcom/zhqy/javademo/Person; ", "property", "Lkotlin/reflect/KProperty; ", "production sources for module app"} ) public final class Delegate { @NotNull public final MyDelegate provideDelegate(@NotNull Person person, @NotNull KProperty property) { Intrinsics.checkParameterIsNotNull(person, "person"); Intrinsics.checkParameterIsNotNull(property, "property"); return new MyDelegate(); } } // MyDelegate.java package com.zhqy.javademo; import android.util.Log; import kotlin.Metadata; import kotlin.jvm.internal.Intrinsics; import kotlin.reflect.KProperty; import org.jetbrains.annotations.NotNull; @Metadata( mv = {1, 1, 10}, bv = {1, 0, 2}, k = 1, d1 = {"\u0000&\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001d\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00062\n\u0010\u0007\u001a\u0006\u0012\u0002\b\u00030\bH\u0086\u0002J%\u0010\t\u001a\u00020\n2\u0006\u0010\u0005\u001a\u00020\u00062\n\u0010\u0007\u001a\u0006\u0012\u0002\b\u00030\b2\u0006\u0010\u000b\u001a\u00020\u0004H\u0086\u0002¨\u0006\f"}, d2 = {"Lcom/zhqy/javademo/MyDelegate; ", "", "()V", "getValue", "", "person", "Lcom/zhqy/javademo/Person; ", "property", "Lkotlin/reflect/KProperty; ", "setValue", "", "s", "production sources for module app"} ) public final class MyDelegate { @NotNull public final String getValue(@NotNull Person person, @NotNull KProperty property) { Intrinsics.checkParameterIsNotNull(person, "person"); Intrinsics.checkParameterIsNotNull(property, "property"); Log.e("getValue", "" + person + ':' + property.getName()); return ""; }public final void setValue(@NotNull Person person, @NotNull KProperty property, @NotNull String s) { Intrinsics.checkParameterIsNotNull(person, "person"); Intrinsics.checkParameterIsNotNull(property, "property"); Intrinsics.checkParameterIsNotNull(s, "s"); Log.e("setValue", "" + person + ':' + property.getName() + ':' + s); } }

感觉就是从创建一个实例变成了通过provideDelegate获取代理类对象
标准库中的代理模式
除了自己实现代理类外,Kotlin标准库中也未我们提供了一些实现好的代理模式。
lazy:lazy关键字在调用响应的属性时才会会执行响应的代理方法,并且该方法只会调用一次。
示例代码如下
class Person(){ var name:String by Delegate() val age by lazy{ Log.e("lazy","lazy") 18 }; } var person=Person(); person.age person.age

测试结果
11-11 17:49:15.047 18817-18817/com.zhqy.javademo E/lazy: lazy

从测试结果可以看出虽然调用了两次 person.age,但lazy的函数体只执行了一次
Delegates.observable:当属性值发生改变时会调用.
示例代码如下
class Person(){ var name:String by Delegate() val age by lazy{ Log.e("lazy","lazy") 18 }; var gender:String by Delegates.observable("男性"){ property, oldValue, newValue ->Log.e("onchange","${property.name}:$oldValue:$newValue") } } var person=Person(); person.gender="女性"

测试结果如下
11-11 17:55:58.443 19182-19182/com.zhqy.javademo E/onchange: gender:男性:女性

其中property包含属性的相关信息,oldValue是原先的属性值,newValue为现在的属性值。
by map:在类中寻找属性名与Map中key相同的再将数值赋给该属性。
示例代码如下
class Student( map:Map){ val name:String by map; val age:Int by map } var map= mapOf("name" to "张三","age" to 18) var student=Student(map) Log.e("student","${student.name}:${student.age}")

测试结果
11-11 18:06:22.516 19482-19482/? E/student: 张三:18

以上就是本文的全部内容

    推荐阅读