委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。Kotlin 直接支持委托模式,更加优雅,简洁,在 Kotlin 中,通过关键字 by 实现委托。
通过委托方式实现接口的方法,实际上是通过动态代理的方式创建一个接口的实现类对象,并委托给要实现这个接口的类,减少接口不需要的方法的重写。
1. 类委托
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。以下实例中派生类 Leader 继承了接口 Work 所有方法,并且委托一个传入的 Clerk 类的对象来执行这些方法。
1 | // 创建接口 |
在 Leader 的声明中,by 关键字表示,将 clerk 保存在 Leader 的对象实例内部,而且编译器将会生成继承自 Work 接口的所有方法, 并将调用转发给 clerk。
2. 动态代理
动态代理允许你在运行时动态地创建代理对象,从而在方法调用前后执行额外的操作。其核心思想是创建一个代理对象来代替原始对象。这个代理对象实现了与原始对象相同的接口,但它可以拦截对原始对象方法的调用,并在调用前后执行自定义的逻辑。与静态代理不同,动态代理不需要在编译时就确定代理类,而是在运行时动态生成。
1 | interface Calculate { |
3. 接口实现
对类委托和动态代理有了一定的了解后,就可以通过这些技术从编码层面将接口不需要的方法去掉了。当实现非 SAM 接口时,需要实现多个方法。大多数情况下,部分方法是开发者用不到的,但仍然需要空实现。例如,为 EditText
添加 TextWatcher
监听。
1 | val edit = findViewById<EditText>(R.id.edit) |
上面的代码实现了监听器的全部方法,但是通过 Kotlin 的委托机制,可以将接口实现委托给方法进行实现,代码如下:
1 | inline fun <reified T : Any> interfaceDelegate(): T { |
在调用处用委托处理,通过这种方式可以自由选择需要实现的方法,而不是实现接口的所有方法。
1 | val edit = findViewById<EditText>(R.id.edit) |
通过 KotlinByteCode 可以查看对应的 Java 实现,代码中可以看到通过动态代理的方式生成了一个 TextWatcher
对象 delegate_0
,并委托此对象完成方法的实现。
1 | EditText edit = (EditText)this.findViewById(2131230891); |
✦ 说明:KotlinByteCode 查看路径**「Android Studio → Tools → Kotlin → Show Kotlin Bytecode」**