探究 Kotlin 类代理

Kotlin 实现类代理是经过 by 关键字,本文尝试讲解类代理在 Kotlin 的具体使用和实现原理。bash

首先,在一个自定义的 View 当中实现一个接口以下:ide

interface CanvasCapabilities {
    fun draw(circle: Circle)
    fun draw(rectangle: Rect)
}

class ArtboardView(context: Context): View(context), CanvasCapabilities
复制代码

如今咱们再建立 CanvasCapabilities 接口的实现:函数

class ArtboardCanvas: CanvasCapabilities {
    override fun draw(circle: Circle) = ...
    override fun draw(rectangle: Rect) = ...
}
复制代码

这个时候,咱们通常会使用接口代理方式实现咱们的逻辑,好比:优化

class ArtboardView(context: Context): View(context), CanvasCapabalities {
    private val artboardCanvas = ArtboardCanvas() // proxy
    
    override fun draw(circle: Circle) = artboardCanvas.draw(circle)
    override fun draw(rectangle: Rect) = artboardCanvas.draw(rectangle)
}
复制代码

这种方式实现,虽然逻辑已经和 View 分离开,可是 View 里面仍是比较混乱。this

那应该怎么办呢?经过关键字 by 实现类代理优化代码spa

class ArtboardView(context: Context): View(context), CanvasCapabilities by ArtboardCanvas()
复制代码

代理类 ArtboardCanvas 直接实现 CanvasCapabilities 接口,不须要再实现内部定义 proxy 方式,代码很是简洁。代理

探究原理

经过反编译成 Java 代码发现原理很是简单,Kotlin 并无作任何黑魔法,只是在内部再生成对应的 delegate 方法。code

public final class ArtboardView extends View implements CanvasCapabilities {

   private final ArtboardCanvas $$delegate_0;

   public ArtboardView(@NotNull Context context) {
      Intrinsics.checkParameterIsNotNull(context, "context");
      super(context);
      this.$$delegate_0 = new ArtboardCanvas();
   }

   public void draw(@NotNull Rect rectangle) {
      Intrinsics.checkParameterIsNotNull(rectangle, "rectangle");
      this.$$delegate_0.draw(rectangle);
   }

   public void draw(@NotNull Circle circle) {
      Intrinsics.checkParameterIsNotNull(circle, "circle");
      this.$$delegate_0.draw(circle);
   }
}
复制代码

这种方式实现,代码很是简洁。可是若是你有不少方法都须要实现,就会对应生成不少方法,可能会影响一些包大小。接口

拓展

构造函数传入类代理ci

class MySet(private val delegate: Set<Long> = HashSet()) : Set<Long> by delegate
复制代码

实现多个类代理

class MySetMap : Set<Long> by HashSet(), Map<Long, Long> by HashMap() {
    override val size: Int
        get() = TODO("not implemented")

    override fun isEmpty(): Boolean {
        TODO("not implemented")
    }
}
复制代码

结论

当你遇到一些场景,类须要对外提供接口,以及须要实现多个接口,经过类代理这种方式抽取逻辑,能够让代码很是简洁。

相关文章
相关标签/搜索