Kotlin泛型数据类如何实现带反序列化的次级构造函数?
问题描述
我定义了如下泛型数据类:
data class ConfigurationDTO<T : Any>( val id: Long, val key: String, var value: T )
我想新增一个次级构造函数,接收String类型的valueStr和KClass来反序列化得到value。但Kotlin要求次级构造函数必须先调用this(),而此时我还没处理出value的值:
constructor(id: Long, key: String, valueStr: String, klazz: KClass<T>) : this(id, key, ??????)
我想要实现的逻辑等价于下面这段无法运行的代码:
// 无法运行 constructor(id: Long, key: String, valueStr: String, klazz: KClass<T>) { val value = // 通过valueStr和klazz执行反序列化初始化逻辑... this(id, key, value) }
也就是先处理参数再调用主构造函数,请问最佳实现方式是什么?
解决方案
Kotlin规定次级构造函数必须优先调用主构造函数(或其他次级构造函数),因此无法先执行参数处理再初始化实例。更符合Kotlin设计习惯的做法是使用工厂方法,而非强行扩展次级构造函数。
方案1:伴生对象工厂方法
在数据类内部定义伴生对象,添加工厂函数处理反序列化逻辑:
data class ConfigurationDTO<T : Any>( val id: Long, val key: String, var value: T ) { companion object { // 通用版本:传入自定义反序列化逻辑 fun <T : Any> fromString( id: Long, key: String, valueStr: String, klazz: KClass<T>, deserializer: (String, KClass<T>) -> T ): ConfigurationDTO<T> { val deserializedValue = deserializer(valueStr, klazz) return ConfigurationDTO(id, key, deserializedValue) } // 内置反序列化逻辑版本(示例用Gson) /* fun <T : Any> fromString( id: Long, key: String, valueStr: String, klazz: KClass<T> ): ConfigurationDTO<T> { val value = Gson().fromJson(valueStr, klazz.java) return ConfigurationDTO(id, key, value) } */ } }
使用示例:
val dto = ConfigurationDTO.fromString( id = 1L, key = "theme", valueStr = "\"dark\"", klazz = String::class, deserializer = { str, _ -> str.removeSurrounding("\"") as T } )
方案2:顶层工厂函数
如果不想把逻辑放在数据类内部,可以定义顶层工厂函数:
fun <T : Any> createConfigurationDTO( id: Long, key: String, valueStr: String, klazz: KClass<T>, deserializer: (String, KClass<T>) -> T ): ConfigurationDTO<T> { val value = deserializer(valueStr, klazz) return ConfigurationDTO(id, key, value) }
使用示例:
val dto = createConfigurationDTO(1L, "theme", "\"dark\"", String::class) { str, _ -> str.removeSurrounding("\"") as T }
方案3:次级构造函数(不推荐)
如果一定要用次级构造函数,可以把反序列化逻辑嵌入主构造函数调用的表达式中,但这种写法可读性差,且无法处理复杂的异常或流程控制:
data class ConfigurationDTO<T : Any>( val id: Long, val key: String, var value: T ) { constructor( id: Long, key: String, valueStr: String, klazz: KClass<T>, deserializer: (String, KClass<T>) -> T ) : this(id, key, deserializer(valueStr, klazz)) }
内容的提问来源于stack exchange,提问作者João Menighin
相关产品推荐
相关产品推荐

