Kotlin委托和Java代理的对比

548 阅读3分钟

java代理 1.代理模式? 定义:代理模式,顾名思义就是提供一个代理类,可以访问原对象并且替原对象进行一些操作。

优点:使用代理模式可以在保证不修改原有类的同时(即满足对扩展开放,对修改关闭的原则),对原有类增加一些功能实现。

2.静态代理

eg:

public interface Person {
    void personJump();
}


public interface Human {
    void humanRun();
}
public class Gsx implements Person, Human {
     final Class clzz = getClass();

 @Override
 public void personJump() {
        System.out.println("gxs personJump");
 }

    @Override
 public void humanRun() {
        System.out.println("gxs humanRun");
 }
}
public class Gsxproxy implements Human, Person {
    private Gsx gsx;


 public Gsxproxy() {
        gsx = new Gsx();
 }



    @Override
 public void humanRun() {
        System.out.println("--before gsx run");
 gsx.humanRun();
 System.out.println("--after gsx run");

 }

    @Override
 public void personJump() {
        System.out.println("--before gsx jump");
 gsx.personJump();
 System.out.println("--after gsx jump");
 }
}
调用 @Test

 val gsxproxy = Gsxproxy()
 gsxproxy.humanRun()
 gsxproxy.personJump()

1.实现方式:代理类和目标类均实现同一接口.

2.有何优点?缺点呢?

2.1)优点:

代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用

代理对象可以扩展目标对象的功能

代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度

2.2)缺点:

因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护

3.和装饰模式很像,区别是?

3.动态代理 eg:

public class MyInvocationHandler implements InvocationHandler {
    Object target;

 void bind(Object target) {
        this.target = target;
 }

    @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getDeclaringClass() == Object.class) return null;

 System.out.println("before");
 method.invoke(target, args);
 System.out.println("after");

 return null;
 }
}
调用:

Person gsx = new Gsx();
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(gsx);
Object proxyInstance = Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class, Human.class}, handler);
((Person) proxyInstance).personJump();
System.out.println("----------------------");
((Human) proxyInstance).humanRun();

1.实现方式:

JDK代理类需要实现InvocationHandler接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起

2.优缺点?

优点:解决了静态代理维护难的缺点

缺点:JDK代理需要目标类实现接口

4.Kotlin委托 官方文档:kotlinlang.org/docs/refere…

1.标准委托 lazy(懒加载属性,不会重复初始化),observable(可对被代理属性进行观察,获得属性改变回调), vetoable(属性值改变前,对值进行拦截),map(代理给map,可作为属性保存)

eg:

val adult: Int by Delegates.vetoable(10) { kProperty: KProperty<*>, old: Int, new: Int ->
 new > old && new > 18
}

2.类委托

eg:

interface HumanKt {
    fun run()
    fun niaoniao()
}


open class HumanKtImp : HumanKt {
    override fun niaoniao() {
        println("humankt imp niaoniao")
    }

    override fun run() {
        println("humankt imp humanRun")
    }

}

fun makeHumanKt(): HumanKt = HumanKtImp() class GsxKt : HumanKt by makeHumanKt() GsxKt 也实现了HumanKt,其具体实现代理给了HumanKtImp,

我们可以观察GsxKt 反编译成java以后的代码,如下:

@Metadata(
   mv = {1, 1, 15},
 bv = {1, 0, 3},
 k = 1,
 d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\t\u0010\u0003\u001a\u00020\u0004H\u0096\u0001J\t\u0010\u0005\u001a\u00020\u0004H\u0096\u0001¨\u0006\u0006"},
 d2 = {"Lcom/lalio/androiddemo/proxy/GsxKt;", "Lcom/lalio/androiddemo/proxy/HumanKt;", "()V", "niaoniao", "", "run", "app"}
)
public final class GsxKt implements HumanKt {
   // $FF: synthetic field
 private final HumanKt $$delegate_0 = HumanKtImpKt.makeHumanKt();

 public void niaoniao() {
      this.$$delegate_0.niaoniao();
 }

   public void run() {
      this.$$delegate_0.run();
 }

可以看到,其实,GsxKt内部持有了HumanKtImpKt实例

3.属性委托

eg:

class Yangmi : Human() {

    val name: String by HumanDelegator()
    val nickName: String by HumanDelegator()
    val age: Int by HumanDelegator()
    

    val subName: String by nameDelegator()
    private fun nameDelegator(): ReadOnlyProperty<Human, String> {
        return object : ReadOnlyProperty<Human, String> {
            override fun getValue(thisRef: Human, property: KProperty<*>): String {
                return "$thisRef,${property.name},杨幂"
 }

        }
    }

    var subnickName: String = ""
 get() = "you ask my name,$field"
 set(value) {
            field = "subnickName is $value"
 }


}

代理类:

class HumanDelegator<T> : ReadOnlyProperty<Human, T> {
    override fun getValue(thisRef: Human, property: KProperty<*>): T {

        return when (property.name) {
            "name" -> "$thisRef name is 杨幂" as T
 "nickName" -> "$thisRef nickName is 小狐狸" as T
 "age" -> 18 as T
 else -> throw NoSuchElementException()
        }

    }
}