You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按策略在多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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:32:21