Kotlin:Enum类上的通用接口,具有从String映射的静态方法

时间:2019-07-18 20:11:21

标签: kotlin enums

假设我有许多如下的枚举类:

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 define interface for enum class values method的答案,但是找不到从接口中的伴随对象访问枚举values()的方法。有一种干净的方法可以做我想要的吗?

1 个答案:

答案 0 :(得分:2)

通过使用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"))
}