I'm new to programming in Kotlin and I've already managed to run into the classic circular dependency issue - I know Kotlin can cope with those but I'd like to know how would I go about changing my design to avoid it. What structures or Kotlin functionality should I use in the following?
import MyClass
interface MyInterface {
fun useMyClass(myInstance: MyClass)
}
import MyInterface
class MyClass(myList: List<MyInterface>) {
val storedList: List<MyInterface> = myList
var myValue: Int = 10
}
I would like MyClass
to store multiple objects which implement MyInterface
, but I would also like each of those objects to reference the class they have been passed to, i.e. each call of useMyClass
would have the signature of useMyClass(this)
.
For example, I could create a class
class ImplementingMyInterfaceClass(): MyInterface {
override fun useMyClass(myInstance: MyClass) {
myInstance.myValue += 10
}
}
and call it somewhere within MyClass
:
ImplementingMyInterfaceClass().useMyClass(this)
Technically I could create another construct in the middle which would be used by MyInterface
and inherited/implemented by MyClass
, but this just doesn't feel correct. Any suggestions?
Note: In my specific issue, it might be helpful to consider each implementation of MyInterface
as a sort of a "modifier" (since it will modify the instance of the class) - MyClass
instances should be aware of its modifiers and each modifier should be able to modify that instance.
It's going to largely depend on what the interface has to do, but you could limit its function argument to some interface that MyClass implements:
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
}
Or your interface can take a property argument:
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)
In other cases where we don't need to both get and set, it could be cleaner to take a more versatile function argument (lambdas could be passed):
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() }