首页 > 解决方案 > Kotlin:Enum 类上的通用接口,具有从 String 映射的静态方法

问题描述

假设我有很多枚举类,如下所示:

enum class Hero(val alias: String) {
    SUPERMAN("Clark Kent"),
    BATMAN("Bruce Wayne");

    companion object {
        fun fromAlias(value: String): Hero? = Hero.values().find { it.alias.equals(value, true) }
    }
}

enum class Villain(val alias: String) {
    TWO_FACE("Harvey Dent"),
    RIDDLER("Edward Nigma");

    companion object {
        fun fromAlias(value: String): Villain? = Villain.values().find { it.alias.equals(value, true) }
    }
}

我希望能够创建一个通用接口来处理该fromAlias方法,以便我仍然可以使用Hero.fromAlias("Bruce Wayne"). 所以我的枚举类将被简化为:

enum class Hero(override val alias: String): AliasedEnum<Hero> {
    SUPERMAN("Clark Kent"),
    BATMAN("Bruce Wayne");
}

enum class Villain(override val alias: String): AliasedEnum<Villain> {
    TWO_FACE("Harvey Dent"),
    RIDDLER("Edward Nigma");
}

我试图将Kotlin 的答案合并为 enum class values method 定义接口,但看不到从接口中的伴随对象访问 enum values() 的方法。有没有一种干净的方法来做我想要的?

标签: kotlinenums

解决方案


companion object通过使用对象可以扩展其他类这一事实,您可以很容易地做到这一点。

几乎任何解决方案都需要两个不同的部分,因为您需要:

  1. 提供功能所需的任何数据的通用接口,因此无论实际实现如何,它都可用。
  2. 一种将共享功能附加到companion object访问权限的方法<Class>.function。这可以是具有所需实现的抽象类,也可以是具有作为扩展功能的实现的标记类。

最后,“最干净”的解决方案可能是这样的:

// Attaching point for the extension function which provides the answer
interface EnumCompanion<T : Enum<T>>

// Marker interface to provide the common data
interface WithAlias {
    val alias: String
}

inline fun <reified T> EnumCompanion<T>.fromAlias(
    value: String
): T? where T : Enum<T>, T : WithAlias {
    return enumValues<T>().find { it.alias == value }
}

// Define the enums and attach the helper to their companion object
enum class Hero(override val alias: String) : WithAlias {
    SUPERMAN("Clark Kent"),
    BATMAN("Bruce Wayne");

    companion object : EnumCompanion<Hero>
}

enum class Villain(override val alias: String) : WithAlias {
    TWO_FACE("Harvey Dent"),
    RIDDLER("Edward Nigma");

    companion object : EnumCompanion<Villain>
}

fun main() {
    println(Hero.fromAlias("Bruce Wayne"))
    println(Villain.fromAlias("Edward Nigma"))
}

推荐阅读