在 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()) }
}
}
与将 labelId
和 alarmed
标志与每个枚举常量相关联的方式相同,您可以添加额外的 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)
}
}
枚举中有很多项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()) }
}
}
与将 labelId
和 alarmed
标志与每个枚举常量相关联的方式相同,您可以添加额外的 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)
}
}