Kotlin - делегирование интерфейса во время выполнения - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть такой интерфейс

interface A{
  fun test()
}

У меня есть класс B1, который реализует A

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

Так же, как B1

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

И у меня естькласс A1, который реализует A

  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 голосов
/ 08 февраля 2019

Вы можете иметь выражение в синтаксисе A1 : A by expression.Выражение оценивается до . Создание класса завершено.Синтаксис делегирования не позволяет переключать реализации.

Вы можете по-прежнему кодировать это вручную или использовать любые динамические прокси-библиотеки, например CGLib, ButeBubuddy.Существует класс java.land.reflect.Proxy, который включен в JVM, вы также можете рассмотреть возможность его использования.Но у него есть побочные эффекты с проверенными исключениями https://jonnyzzz.com/blog/2018/11/22/proxy/

Последняя альтернатива - генерировать код во время компиляции.KotlinPoet может быть полезным для этого.Вы можете включить эту задачу в свой Maven или Gradle билд.Преимущество заключается в том, что вы будете контролировать работу делегирования и не будете тратить на это время, когда выполняется код https://github.com/square/kotlinpoet

0 голосов
/ 08 февраля 2019

Честно говоря, я не думаю, что стоит делать это, используя ключевое слово делегирования 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"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...