在 Kotlin 中使用枚举时如何改进冗长的代码?

How can I improve the verbose code when I use enum in Kotlin?

枚举中有很多项class,我发现函数中有很多冗长的代码fun getLevel

我该如何改进它?

代码A

enum class ELevel(private val labelId: Int, val alarmed: Boolean){

   Normal(R.string.Normal,false),
   Leaves(R.string.Leaves,false),
   Whispering(R.string.Whispering,false),
   Quiet(R.string.Quiet,false),
   Refrigerator(R.string.Refrigerator,false),
   Electric(R.string.Electric,false),
   Washing(R.string.Washing,true),
   Alarm(R.string.Alarm,true),
   Subway(R.string.Subway ,true),
   Factory(R.string.Factory,true),
   Car(R.string.Car,true),
   Ambulance(R.string.Ambulance,true);

   fun getLabel(mContext: Context) =  mContext.getString(labelId)

   companion object {
        fun getLevel(soundValue: Double): ELevel {
            var temp = Normal
            val i = soundValue.toInt()

            if (i in 1..10) {
                temp = Normal
            }

            if (i in 11..20) {
                temp =  Leaves
            }

            ...

            if (i in 101..110) {
                temp = Car
            }

            if (i in 111..120) {
                temp =  Ambulance
            }


            return temp
        }
   }

一种方法是创建一个抽象值范围并为每个枚举定义它。之后你可以简单地检查并获得第一个枚举,你的 soundValue 在他的范围内。

enum class ELevel(private val labelId: Int, val alarmed: Boolean) {

    Normal(R.string.Normal, false) {
        override val range: IntRange = 1..10
    },
    Leaves(R.string.Leaves, false) {
        override val range: IntRange = 11..20
    },
    Whispering(R.string.Whispering, false) {
        override val range: IntRange = ...
    },
    Quiet(R.string.Quiet, false) {
        override val range: IntRange = ...
    },
    Refrigerator(R.string.Refrigerator, false) {
        override val range: IntRange = ...
    },
    Electric(R.string.Electric, false){
        override val range: IntRange = ...
    },
    Washing(R.string.Washing, true){
        override val range: IntRange = ...
    },
    Alarm(R.string.Alarm, true){
        override val range: IntRange = ...
    },
    Subway(R.string.Subway, true){
        override val range: IntRange = ...
    },
    Factory(R.string.Factory, true){
        override val range: IntRange = ...
    },
    Car(R.string.Car, true) {
        override val range: IntRange = 101..110
    },
    Ambulance(R.string.Ambulance, true) {
        override val range: IntRange = 111..120
    };

    fun getLabel(mContext: Context) = mContext.getString(labelId)

    abstract val range: IntRange

    companion object {
        fun getLevel(soundValue: Double): ELevel =
            values().first { it.range.contains(soundValue.toInt()) }
    }
}

与将 labelIdalarmed 标志与每个枚举常量相关联的方式相同,您可以添加额外的 maxSoundLevel 属性:

enum class ELevel(
    private val labelId: Int,
    val alarmed: Boolean,
    val maxSoundLevel: Int,
){

    Normal(R.string.Normal,false, 10),
    Leaves(R.string.Leaves,false, 20),
    ...
}

那么你可以这样做:

companion object {
    fun getLevel(soundValue: Double): ELevel =
        // assuming the max sound levels are in ascending order
        values().firstOrNull { soundValue.toInt() <= it.maxSoundLevel }
            // if there is no match, throw exception. You can also just return the nullable ELevel
            ?: throw IllegalArgumentException("Unknown sound")
}

如果字符串的 ID 与枚举值名称完全匹配,您还可以使用标识符 look-up 来进一步缩短代码。

enum class ELevel(
    val alarmed: Boolean,
    private val maxSoundLevel: Int,
){

    Normal(false, 10),
    Leaves(false, 20),
    //...
    ;

    private var labelId = 0

    fun getLabel(context: Context){
        if (labelId == 0) {
            labelId = context.resources.getIdentifier(name, "id", context.packageName)
        }
        return context.getString(labelId)
    }
}