最近看到一种很有意思的类写法:
class ExampleProxy(private val method: (String) -> Unit) : (String) -> Unit {
override fun invoke(param: String) {
println("proxy do something...")
method(param)
}
}
定义了一个ExampleProxy
类,返回类型是一个函数类型定义(String) -> Unit
。类内重载了invoke
操作符,参数类型必需和类返回的函数类型定义中的参数类型是一致的(有点绕)。
FunctionX
注意到,如果类返回类型是函数定义的话,invode
方法是必需重载的。可以看到如果注释掉invoke
方法,IDE会提示如下:
Function1
接口的invode方法,所以我之前的描述是有问题的:ExampleProxy
并不是返回函数定义(String) -> Unit
,而是实现了接口Function1
。换一个角度看,kotlin内形如(R,..)->T
的函数类型等价于FunctionX
,R,..
参数数量即为X
:
Functions.kt
可以看到最多支持到22个参数函数类型定义,只是写法...确实很简单粗暴...
实现FunctionX的类可以做什么?
回到正题,前文实现了Function1
的ExampleProxy
类,其每个实例对象即代表一个函数引用。由此我们可以在类构造函数内传入相同函数类型定义的函数引用,实现函数层面的动态代理。
函数级代理
定义一个类A
:
class A {
fun printInfo(s: String) {
println("I'm $s")
}
}
以被代理函数printInfo
的引用作为构造参数实例化出一个ExampleProxy
类的对象printInfoProxy
。printInfoProxy("abc")
方式的调用效果等同于printInfoProxy.invoke("abc")
。执行main方法:
fun main(args: Array<String>) {
val printInfoProxy = ExampleProxy(A()::printInfo)
printInfoProxy("abc")
}
打印结果:
proxy do something...
I'm abc
可以看到,由此实现了代理的效果。
实际上这是一种形式受限的动态代理,ExampleProxy
只可以代理(String) -> Unit
类型的函数。