前言
本文简要介绍代理模式在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
以上就是本文的全部内容