I have an interface that stores the flags for the features that were enabled or no and that has a function to return the current values of the properties in this map:
interface IModuleEnabler {
val module_1_parameter_1: Boolean
val module_1_parameter_2: Boolean
val module_1_parameter_3: Boolean
val module_2_parameter_1: Boolean
val module_2_parameter_2: Boolean
val module_2_parameter_3: Boolean
fun getPropertiesMap(): Map<String, List<Pair<String, Boolean>>> {
var propertiesMap: Map<String, List<Pair<String, Boolean>>> = mutableMapOf()
var properties = listOf<Pair<String, Boolean>>(
Pair<String, Boolean>("module_1_parameter_1", module_1_parameter_1),
Pair<String, Boolean>("module_1_parameter_2", module_1_parameter_2),
Pair<String, Boolean>("module_1_parameter_3", module_1_parameter_3)
)
propertiesMap = propertiesMap.plus("Module1" to properties)
return propertiesMap
}
}
This interface has a default class, which is implementing it and the custom class based on default to override the default values, if need. However, the issue is that the function getPropertiesMap() has always the default values and not the overriden ones. Is there a way to force update this function to have the actual values? Link to the playground - Kotlin Playground
CodePudding user response:
This is a shortcoming of delegates in Kotlin. The functions in the delegate have no knowledge of the class that is using it as a delegate and it will ignore overridden functions in that class.
It would be better to implement your getPropertiesMap
function as an extension function so it cannot be overridden. This will fix your problem, but it's better practice anyway. When you have it defined inside your interface, it is left open
and practically invites users to override it. Also, you're using a kind of convoluted way of creating a map.
fun IModuleEnabler.getPropertiesMap(): Map<String, List<Pair<String, Boolean>>> {
val properties = listOf(
Pair("module_1_parameter_1", module_1_parameter_1),
Pair("module_1_parameter_2", module_1_parameter_2),
Pair("module_1_parameter_3", module_1_parameter_3)
)
return mapOf("Module1" to properties)
}
I would do it without all the overriding and delegation anyway. Allow the Default implementation to set the values from the constructor. The custom implementation can simply call the super-constructor with the different values it wants.
open class DefaultFeatureEnabler(
override val module_1_parameter_1: Boolean = false,
override val module_1_parameter_2: Boolean = false,
override val module_1_parameter_3: Boolean = false,
override val module_2_parameter_1: Boolean = false,
override val module_2_parameter_2: Boolean = false,
override val module_2_parameter_3: Boolean = false
): IModuleEnabler
class CustomFeatureEnabler: DefaultFeatureEnabler(
module_1_parameter_3 = true,
module_2_parameter_1 = true
)
CodePudding user response:
This is because CustomFeatureEnabler
delegates getPropertiesMap
to DefaultFeatureEnabler
. You can fix it by overriding getPropertiesMap
in classes where you use delegation
class CustomFeatureEnabler : IModuleEnabler by DefaultFeatureEnabler() {
override val module_1_parameter_3: Boolean get() = true
override val module_2_parameter_1: Boolean get() = true
override fun getPropertiesMap() = super.getPropertiesMap() // <---
}