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

如何使用泛型实现输入类型安全的Kotlin工厂模式?

最优解决方案核心思路

利用Kotlin的KClass运行时类型信息,提前让每个Provider声明自己支持的输入类型,工厂直接通过类型匹配找到对应Provider,完全规避不安全的类型转换异常,无需try-catch捕获。


分步代码改造

  1. 修改Provider接口,新增支持类型声明
interface ExampleFragmentProvider<T: ExampleInput> {
    // 声明当前Provider可处理的输入类型
    val supportedType: KClass<T>
    suspend fun provide(pageType: T) : Fragment
}
  1. 调整Provider实现类,补充supportedType配置
    以HomepageProvider为例,其余Provider同理配置:
internal class ExampleHomepageProvider @Inject constructor() :
    ExampleFragmentProvider<ExampleInput.Homepage> {
    // 绑定当前Provider对应的输入类型
    override val supportedType = ExampleInput.Homepage::class
    override suspend fun provide(pageType: ExampleInput.Homepage): Fragment {
        TODO()
    } 
}
  1. 重写工厂实现,通过类型匹配查找Provider
class ExampleFragmentFactoryImpl @Inject constructor(
    private val providers: List<ExampleFragmentProvider<out ExampleInput>>
): ExampleFragmentFactory {

    @Suppress("UNCHECKED_CAST")
    override suspend fun <T: ExampleInput> create(
        pageType: T
    ): Fragment {
        val targetType = pageType::class
        providers.forEach { provider ->
            if (provider.supportedType == targetType) {
                // 此处类型转换100%安全,已通过supportedType验证对应关系
                return (provider as ExampleFragmentProvider<T>).provide(pageType)
            }
        }
        throw IllegalStateException("could not create Fragment for pageType=$pageType")
    }
}

性能优化方案

如果Provider数量较多,可以在工厂初始化时直接构建类型到Provider的映射表,避免每次调用都遍历列表:

class ExampleFragmentFactoryImpl @Inject constructor(
    providers: List<ExampleFragmentProvider<out ExampleInput>>
): ExampleFragmentFactory {
    // 初始化时预构建映射表,查询复杂度从O(n)降为O(1)
    private val providerMapping = providers.associateBy { it.supportedType }

    @Suppress("UNCHECKED_CAST")
    override suspend fun <T: ExampleInput> create(pageType: T): Fragment {
        val provider = providerMapping[pageType::class] as? ExampleFragmentProvider<T>
            ?: throw IllegalStateException("could not create Fragment for pageType=$pageType")
        return provider.provide(pageType)
    }
}

方案说明

  • 所有类型校验都在编译+运行时双重保障,@Suppress("UNCHECKED_CAST")是安全的,不会出现类型转换异常,无需try-catch包裹
  • 符合开闭原则:新增输入类型仅需新增对应Provider实现,工厂侧无需修改任何代码
  • 因为输入是sealed class,可以保证所有可传入的类型都有对应的Provider覆盖,不会出现遗漏

内容的提问来源于stack exchange,提问作者ceedee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:45:02