Kotlin-运行时的接口委托

时间:2019-02-08 14:52:11

标签: java android kotlin delegates

我有这样的界面

interface A{
  fun test()
}

我有一个实现A的类B1

class B1: A
{
    override fun test()
  {
          print("B1")
   }
}

类似于B1

class C1: A
{
    override fun test()
  {
    print("C1")
  }
}

我有一个实现A的类A1

  class A1 (var test : Test) : A by test
{
      init
  {
      // Based on condition  i need to decide the delegation either B1 or C1
  }
}
fun main(){
A1(B1()) // By default am sending the object of B1
}

我的问题是我需要根据某些条件在运行时更改init的委托。 有什么办法可以做到吗?

2 个答案:

答案 0 :(得分:1)

您可能有一个A1 : A by expression语法的表达式。在类构造完成之前,在之前对表达式求值。委托语法不允许切换实现。

您仍可以手动编写代码,或使用任何动态代理库,例如CGLib,ButeBubuddy。 JVM中包含java.land.reflect.Proxy类,您也可以考虑使用它。但是它具有检查异常https://jonnyzzz.com/blog/2018/11/22/proxy/

的副作用

最后一种选择是在编译时生成代码。 KotlinPoet可能对此有所帮助。您可以将该任务包含在您的Maven或Gradle构建中。好处是您可以控制委派的工作方式,并且不会在代码运行时浪费时间。 https://github.com/square/kotlinpoet

答案 1 :(得分:0)

老实说,我不认为使用by委托关键字来做到这一点是不值得的。相反,我只是在private var内部为A存储A1并手动转发呼叫。像这样:

class A1 : A {
    private var aDelegate: A

    init { 
        aDelegate = if (condition) B1() else C1()
    }

    override fun test() {
        aDelegate.test()
    }
}

也就是说,您可以使用一个选项,尽管我不一定会推荐它。它需要为A的调用者提供A1的自定义可变实现,但是保留为可选,以便不必使用它:

class MutableA(var aDelegate: A = EmptyA()) : A {
    override fun test() {
        aDelegate.test()
    }

    class EmptyA : A { 
        override fun test() { }
    }
}

class A1(private val mutableA: MutableA = MutableA()) : A by delegate {
    init {
        mutableA.aDelegate = if (condition) B1() else C1()
    }
}

因此,您可以将其初始化,例如:

class A1(flag: Boolean, private val mutableA: MutableA = MutableA()) : A by delegate {
    init { 
        mutableA.aDelegate = if (flag) B1() else C1()
    }
}

fun main() {
    A1(true).test() // prints "B1"
    A1(false).test() // prints "C1"
}