Kotlin如何设计支持多别名匹配的指标枚举类结构
Kotlin枚举支持多别名匹配的实现方案
核心实现思路
不修改Kotlin枚举原生valueOf逻辑,在枚举伴生对象中预构建全名称(主名称+所有别名)到枚举实例的哈希查找表,类加载阶段一次性初始化,后续查找时间复杂度O(1),调用方式和原生valueOf完全对齐。
完整枚举定义
enum class FieldProfileMetrics(val mainName: String, vararg val aliases: String) { CountMissing("countMissing", "count_missing"), Count("count"), CountPopulated("countPopulated", "count_populated"), CountDistinct("countDistinct", "count_distinct", "approxCountDistinct"), CountMean("mean", "count_mean"); companion object { // 全局查找映射,key为所有合法的指标名(主名+别名),value为对应枚举实例 private val nameMapping = buildMap { values().forEach { metric -> // 写入主名称映射 put(metric.mainName, metric) // 写入所有别名映射 metric.aliases.forEach { alias -> put(alias, metric) } } } /** * 支持别名匹配的自定义valueOf,签名与原生枚举valueOf保持一致 * @throws IllegalArgumentException 传入名称无匹配时抛出,与原生逻辑行为对齐 */ fun valueOf(name: String): FieldProfileMetrics { return nameMapping[name] ?: throw IllegalArgumentException( "Invalid metric name: $name, valid metrics are: ${entries.joinToString { it.mainName }}" ) } } }
如果需要兼容大小写不敏感的匹配场景,只需要在写入映射和查找时统一对字符串做lowercase()处理即可。
方案优势
- 性能高:映射表在类加载时一次性构建完成,后续每次查找都是O(1)哈希查询,无运行时循环遍历枚举的开销,性能和原生
valueOf基本一致 - 调用成本低:完全对齐原生枚举的调用习惯,业务侧直接使用
FieldProfileMetrics.valueOf(metricName)即可,不需要修改原有调用代码 - 可维护性强:新增、修改指标只需要调整枚举项的主名、别名配置,不需要修改任何匹配分支逻辑,彻底替换原有硬编码
when判断 - 行为一致:匹配失败时抛出和原生枚举相同类型的
IllegalArgumentException,不会引入额外的异常处理逻辑
可选扩展:收敛指标取值逻辑
可以把原来硬编码在when分支里的取值逻辑直接收敛到枚举内部,彻底消灭业务侧的分支判断:
enum class FieldProfileMetrics(val mainName: String, vararg val aliases: String) { CountMissing("countMissing", "count_missing") { override fun getValue(profile: FieldProfile) = profile.countMissing.toDouble().right() }, Count("count") { override fun getValue(profile: FieldProfile) = profile.count.toDouble().right() }, CountPopulated("countPopulated", "count_populated") { override fun getValue(profile: FieldProfile) = profile.countPopulated.toDouble().right() }, CountDistinct("countDistinct", "count_distinct", "approxCountDistinct") { override fun getValue(profile: FieldProfile) = profile.countDistinct.toDouble().right() }, CountMean("mean", "count_mean") { override fun getValue(profile: FieldProfile) = profile.getDecimalData("mean").right() }; abstract fun getValue(profile: FieldProfile): Either<*, Double> companion object { // 此处保留之前的nameMapping和自定义valueOf逻辑即可 } }
收敛后业务侧代码可以简化为一行,不需要维护任何分支:
val result = FieldProfileMetrics.valueOf(metricName).getValue(currentFieldProfile)
内容的提问来源于stack exchange,提问作者Akshay Hazari
相关产品推荐
相关产品推荐

