探究 Kotlin 类代理

作者: simpleeeeee | 来源:发表于2019-04-17 14:25 被阅读13次

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

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

    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 里面还是比较混乱。

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

    class ArtboardView(context: Context): View(context), CanvasCapabilities by ArtboardCanvas()
    

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

    探究原理

    通过反编译成 Java 代码发现原理非常简单,Kotlin 并没有做任何黑魔法,只是在内部再生成对应的 delegate 方法。

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

    这种方式实现,代码非常简洁。但是如果你有很多方法都需要实现,就会对应生成很多方法,可能会影响一些包大小。

    拓展

    构造函数传入类代理

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

    结论

    当你遇到一些场景,类需要对外提供接口,以及需要实现多个接口,通过类代理这种方式抽取逻辑,可以让代码非常简洁。

    相关文章

      网友评论

        本文标题:探究 Kotlin 类代理

        本文链接:https://www.haomeiwen.com/subject/hscnwqtx.html