Kotlin: динамически выбирать функцию объекта-компаньона - PullRequest
0 голосов
/ 26 марта 2020

Мой класс Enum и сопутствующий объект:

enum class Temperature(val names: List<String>) {
    Celsius(listOf("degree Celsius", "degrees Celsius", "celsius", "dc", "c")),
    Kelvin(listOf("Kelvin", "Kelvins", "k")),
    Fahrenheit(listOf("degree Fahrenheit", "degrees Fahrenheit", "fahrenheit", "df", "f"));

    companion object Conversion {
        fun CelsiusToKelvin(c: Double) = c + 273.15
        fun CelsiusToFahrenheit(c: Double) = (c * 9 / 5) + 32
        fun FahrenheitToKelvin(f: Double) = (f + 459.67) * 5 / 9
        fun FahrenheitToCelsius(f: Double) = (f - 32) * 5 / 9
        fun KelvinToCelsius(K: Double) = K - 273.15
        fun KelvinToFahrenheit(K: Double) = K * 9 / 5 - 459.67
    }
}

Я получаю входную температуру в шкале, которую мне нужно преобразовать в другой выходной масштаб. Есть ли способ динамического вызова функций объекта-компаньона на основе масштабов ввода и вывода?

Например:

var convert = "CelsiusToKelvin"
val value = 36.9
val myFunc = Temperature.getFunction(convert)
val myOutput = myFunc(value)

Это должно вызвать функцию Temperature.CelsiusToKelvin.

Я знаю, что могу проверить ввод с помощью операторов if или when и вручную вызвать нужную функцию. Но возможно ли это без этого?


Редактировать 1:

Я решил это, используя изменение функции:

companion object Conversion {
        fun convert(a:String,b:String,c:Double) = when {
            a == "Celsius" && b == "Kelvin" -> c + 273.15
            a == "Celsius" && b == "Fahrenheit" -> (c * 9 / 5) + 32
            a == "Fahrenheit" && b == "Kelvin" -> (c + 459.67) * 5 / 9
            a == "Fahrenheit" && b == "Celsius" -> (c - 32) * 5 / 9
            a == "Kelvin" && b == "Celsius" -> c - 273.15
            a == "Kelvin" && b == "Fahrenheit" -> c * 9 / 5 - 459.67
            else -> 0.0
        }
    }

Но я хочу знать если бы то, что я изначально хотел сделать, было возможно

1 Ответ

2 голосов
/ 26 марта 2020

Я думаю, что лучший подход, если вам нужно использовать String s, это динамически определять константу , и каждая константа обеспечивает необходимые функции преобразования. Например:

// Note: Didn't include your "names" property
enum class Temperature {
    Celsius {
        override fun toKelvin(value: Double) = value + 273.15
        override fun toFahrenheit(value: Double) = (value * 9.0 / 5.0) + 32.0
    },
    Kelvin {
        override fun toCelsius(value: Double) = value - 273.15
        override fun toFahrenheit(value: Double) = value * 9.0 / 5.0 - 459.67
    },
    Fahrenheit {
        override fun toCelsius(value: Double) = (value - 32.0) * 5.0 / 9.0
        override fun toKelvin(value: Double) = (value + 459.67) * 5.0 / 9.0
    };

    open fun toCelsius(value: Double) = value
    open fun toKelvin(value: Double) = value
    open fun toFahrenheit(value: Double) = value

    fun convert(value: Double, target: Temperature) = when (target) {
        Celsius -> toCelsius(value)
        Kelvin -> toKelvin(value)
        Fahrenheit -> toFahrenheit(value)
    }

    companion object {

        fun convert(source: String, target: String, value: Double) =
            valueOf(source).convert(value, valueOf(target))
    }
}

Метод valueOf, который неявно добавляется компилятором, выдаст IllegalArgumentException, если строка не совпадает с именем константы перечисления точно . Ваш код имеет аналогичное требование, за исключением того, что вы возвращаете 0, если нет совпадения. Я лично предпочитаю исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...