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")
    }

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, "<set-?>");
      this.name$delegate.setValue(this, $$delegatedProperties[0], var1);
   }
}

从字节码中可以看到声明了代理类MyDelegate的一个对象,并在get和set方法中分别调用了getVale和setValue方法实现代理功能。
当然也可以使用关键字

class Person(){
    var name:String by Delegate()
}

class Delegate(){
    
    operator  fun 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", "<set-?>", "", "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, "<set-?>");
      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<K,V>中key相同的再将数值赋给该属性。

示例代码如下

class Student( map:Map<String,Any>){
    val name:String by map;
    val age:Int by map

 }

 var map= mapOf<String,Any>("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

以上就是本文的全部内容

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容