如何让Kit接口的observe方法仅接受Registry内的ExperimentVariable参数?
实现方案:通过专属标记类型限制参数范围
要让Kit.observe()仅接受Registry内的ExperimentVariable实例,可以通过给Registry内的实例添加专属私有标记的方式,在编译阶段拦截非法调用。以下是具体实现步骤:
1. 调整ExperimentVariable的定义
给ExperimentVariable增加一个类型参数,用于携带标记信息,以此区分不同来源的实例:
// 新增类型参数M,用于标记实例来源 class ExperimentVariable<T, out M : Any>( val key: String, val enabled: Boolean, val defaultValue: T, val source: String ) class ExperimentVariableBuilder<T> { private var key: String = "" private var enabled: Boolean = false private var defaultValue: T? = null private var source: String = "" fun setKey(key: String) = apply { this.key = key } fun setEnabled(enabled: Boolean) = apply { this.enabled = enabled } fun setDefaultValue(defaultValue: T) = apply { this.defaultValue = defaultValue } fun setSource(source: String) = apply { this.source = source } // 新增带标记的build方法,生成绑定标记的ExperimentVariable fun <M : Any> build(marker: M): ExperimentVariable<T, M> { return ExperimentVariable(key, enabled, defaultValue!!, source) } }
2. 修改Registry,给内部实例添加私有标记
在Registry中定义一个私有对象作为专属标记,所有内部生成的ExperimentVariable都携带这个标记:
object Registry { // 私有标记,仅Registry内部可访问 private val REGISTRY_MARKER = object : Any() {} val SOME_KEY = ExperimentVariableBuilder<Boolean>() .setKey("some_key") .setEnabled(true) .setDefaultValue(false) .setSource("remote") .build(REGISTRY_MARKER) // 绑定私有标记 val SOME_KEY_1 = ExperimentVariableBuilder<String>() .setKey("some_key_1") .setEnabled(true) .setDefaultValue("some_string") .setSource("remote") .build(REGISTRY_MARKER) // 绑定私有标记 }
3. 限制Kit.observe()的参数类型
将observe()的参数类型限定为携带Registry私有标记的ExperimentVariable,这样只有Registry内的实例能匹配该类型:
interface Kit { // 仅接受带Registry私有标记的ExperimentVariable fun observe(experimentsVariable: ExperimentVariable<*, Registry.REGISTRY_MARKER>): Observable<String> // get方法仍可接受所有类型的ExperimentVariable(如需保留原有逻辑) fun get(experimentsVariable: ExperimentVariable<*, *>): String }
效果验证
- 合法调用:
kit.observe(Registry.SOME_KEY)可正常编译,参数携带了正确的私有标记。 - 非法调用:
kit.observe(AnotherRegistry.Another_Key)直接触发编译错误,因为外部Registry无法获取Registry.REGISTRY_MARKER,生成的实例类型不匹配。
内容的提问来源于stack exchange,提问作者Shrikant
相关产品推荐
相关产品推荐

