如何按策略在多Config对象中获取非空嵌套属性值?
问题描述
我们有嵌套的Kotlin数据类,以及两个可能为空的配置对象remoteConfig和localConfig,通过getConfigObject()根据状态返回配置,但当前实现仅能在整个Config对象为空时降级,无法处理Config非空但嵌套属性为空的场景——比如状态"one"下需要优先取remote的嵌套属性,属性为空时再fallback到local的对应属性。
相关代码定义如下:
data class Config(val service : Service?, val section : Section?) data class Service(val name : String?, val value : String?) data class Section(val id : Int?, val title : String?) val remoteConfig : Config? = Config() val localConfig : Config? = Config() fun getConfigObject(): Config? { return when(state){ "one" -> remoteConfig ?: localConfig "two" -> remoteConfig "three" -> localConfig } }
解决方案
以下是几种无需重复代码、符合Kotlin最佳实践的实现方式,均避免使用反射(反射存在性能损耗与维护成本):
方案1:属性级通用提取函数(最直接)
封装核心的状态判断与空值降级逻辑,针对每个嵌套属性编写复用的提取函数,避免重复编写when分支。
// 通用属性提取逻辑,根据状态返回优先级最高的非空属性值 private fun <T> getProperty(remoteProp: T?, localProp: T?): T? { return when(state) { "one" -> remoteProp ?: localProp "two" -> remoteProp "three" -> localProp } } // 具体属性的获取函数 fun getServiceName(): String? { val remoteName = remoteConfig?.service?.name val localName = localConfig?.service?.name return getProperty(remoteName, localName) } fun getSectionTitle(): String? { val remoteTitle = remoteConfig?.section?.title val localTitle = localConfig?.section?.title return getProperty(remoteTitle, localTitle) } fun getServiceValue(): String? { val remoteValue = remoteConfig?.service?.value val localValue = localConfig?.service?.value return getProperty(remoteValue, localValue) }
该方案逻辑清晰,每个属性的提取都复用了核心规则,完全满足属性级别的降级需求。
方案2:构建合并后的代理Config对象(适合多属性频繁访问场景)
如果需要频繁访问多个嵌套属性,可以创建一个合并后的代理Config对象,其每个属性都遵循状态与空值规则从remote或local中获取,上层调用方无需感知降级逻辑。
// 复用方案1的通用属性提取函数 private fun <T> getProperty(remoteProp: T?, localProp: T?): T? { return when(state) { "one" -> remoteProp ?: localProp "two" -> remoteProp "three" -> localProp } } fun getMergedConfig(): Config { val mergedService = Service( name = getProperty(remoteConfig?.service?.name, localConfig?.service?.name), value = getProperty(remoteConfig?.service?.value, localConfig?.service?.value) ) val mergedSection = Section( id = getProperty(remoteConfig?.section?.id, localConfig?.section?.id), title = getProperty(remoteConfig?.section?.title, localConfig?.section?.title) ) return Config(mergedService, mergedSection) }
上层调用可直接通过getMergedConfig().service?.name获取属性,代码简洁统一。
方案3:Kotlin委托属性(优雅的类内属性访问方式)
如果是在类中访问配置属性,可使用委托属性封装提取逻辑,进一步简化代码:
class ConfigAccessor { private val state: String = "one" // 假设状态在此维护 // 封装委托逻辑 private fun <T> propertyDelegate(remoteGetter: () -> T?, localGetter: () -> T?): ReadOnlyProperty<ConfigAccessor, T?> { return ReadOnlyProperty { _, _ -> when(state) { "one" -> remoteGetter() ?: localGetter() "two" -> remoteGetter() "three" -> localGetter() } } } // 声明委托属性 val serviceName: String? by propertyDelegate( { remoteConfig?.service?.name }, { localConfig?.service?.name } ) val sectionTitle: String? by propertyDelegate( { remoteConfig?.section?.title }, { localConfig?.section?.title } ) }
使用时直接通过configAccessor.serviceName即可获取符合规则的属性值,逻辑完全封装,代码简洁优雅。
注意事项
- 状态维护:确保
state的访问线程安全,多线程环境下需用线程安全的存储方式。 - 空值扩展:可根据业务需求在
getProperty函数中添加默认值(如返回空字符串而非null)。
内容的提问来源于stack exchange,提问作者Hamed
相关产品推荐
相关产品推荐

