Как вы решаете круговой импорт в Kotlin - PullRequest
0 голосов
/ 26 марта 2020

Я новичок в программировании на Kotlin, и мне уже удалось столкнуться с проблемой круговой зависимости classi c - я знаю, Kotlin может справиться с этим, но я хотел бы знать, как бы я go об изменении моего дизайна, чтобы избежать этого. Какие структуры или Kotlin функциональность я должен использовать в следующих случаях?

import MyClass

interface MyInterface {
    fun useMyClass(myInstance: MyClass)
}
import MyInterface

class MyClass(myList: List<MyInterface>) {
    val storedList: List<MyInterface> = myList
    var myValue: Int = 10
}

Я хотел бы MyClass для хранения нескольких объектов, которые реализуют MyInterface, но я также хотел бы, чтобы каждый из них объекты для ссылки на класс, которому они были переданы, то есть каждый вызов useMyClass будет иметь подпись useMyClass(this).

Например, я мог бы создать класс

class ImplementingMyInterfaceClass(): MyInterface {
    override fun useMyClass(myInstance: MyClass) {
         myInstance.myValue += 10
    }
}

и вызвать его где-нибудь внутри MyClass:

ImplementingMyInterfaceClass().useMyClass(this)

Технически я мог бы создать другую конструкцию в середине, которая была бы использована MyInterface и унаследована / реализована MyClass, но это просто не чувствую себя правильно. Любые предложения?

Примечание: В моем конкретном c вопросе, возможно, было бы полезно рассматривать каждую реализацию MyInterface как своего рода «модификатор» (так как он будет изменять экземпляр класса) - MyClass экземпляры должны знать о своих модификаторах, и каждый модификатор должен иметь возможность изменять этот экземпляр.

1 Ответ

1 голос
/ 26 марта 2020

Это будет во многом зависеть от того, что должен делать интерфейс, но вы можете ограничить его аргумент функции некоторым интерфейсом, который реализует MyClass:

interface MyInterface {
    fun increaseSomeValue(someValueHolder: MySubInterface)

    interface MySubInterface {
        var myValue: Int
    }
}

class MyClass(myList: List<MyInterface>): MyInterface.MySubInterface {
    val storedList: List<myInterface> = myList
    override var myValue: Int = 10
}

Или ваш интерфейс может принимать аргумент свойства:

interface MyInterface {
    fun increaseSomeValue(someValue: KMutableProperty<Int>)
}

class MyInterfaceImpl: MyInterface {
    override fun increaseSomeValue(someValue: KMutableProperty<Int>) {
        someValue.setter.call(someValue.getter.call() + 10)
    }
}

// from MyClass:
storedList.first().printSomeValue(::myValue)

В других случаях, когда нам не нужно как получать, так и устанавливать, может быть более понятным принять более универсальный аргумент функции (можно передавать лямбды):

interface MyInterface {
    fun printSomeValue(valueProvider: () -> Int)
}

class MyInterfaceImpl: MyInterface {
    override fun printSomeValue(valueProvider: () -> Int) {
        println(valueProvider())
    }
}

// from MyClass:
storedList.first().printSomeValue(::myValue)
// or
storedList.first().printSomeValue { 1..10.random() }
...