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

如何创建Kotlin泛型工厂生成子类,减少ViewModel样板代码?

解决方案

一、通用泛型基工厂实现

针对多数ViewModel仅需传入arguments的场景,实现通用工厂类避免重复编写样板代码:

open class GenericViewModelFactory<VM : BaseViewModel<T>, T : BaseViewModel.In>(
    private val args: T,
    private val creator: (T) -> VM
) : BaseViewModel.Factory<VM>() {
    override fun get(): VM = creator(args)
}

// 配合inline reified函数自动获取构造函数,进一步简化调用
inline fun <reified VM : BaseViewModel<T>, reified T : BaseViewModel.In> genericFactory(args: T): GenericViewModelFactory<VM, T> {
    val constructor = VM::class.primaryConstructor ?: error("ViewModel必须定义主构造函数")
    return GenericViewModelFactory(args) { constructor.call(it) }
}

使用时子类无需再内部编写Factory,直接通过genericFactory获取实例即可。

二、统一伴生对象Factory调用方式

通过接口约定实现子类伴生对象的Factory入口统一:

修改BaseViewModel

abstract class BaseViewModel<T : BaseViewModel.In>(val arguments: T) : ViewModel() {
    interface In

    abstract class Factory<X : BaseViewModel<*>> : ViewModelProvider.Factory {
        abstract fun get(): X

        override fun <U : ViewModel> create(
            modelClass: KClass<U>,
            extras: CreationExtras
        ): U {
            return get() as U
        }
    }

    // 定义工厂提供者接口,子类伴生对象需实现此接口
    interface ViewModelFactoryProvider<VM : BaseViewModel<T>, T : BaseViewModel.In> {
        fun createFactory(args: T): Factory<VM>
    }

    companion object {
        inline fun <reified VM : BaseViewModel<T>, reified T : BaseViewModel.In> factory(args: T): Factory<VM> {
            val provider = VM::class.companionObjectInstance as? ViewModelFactoryProvider<VM, T>
                ?: error("${VM::class.simpleName}的伴生对象必须实现ViewModelFactoryProvider接口")
            return provider.createFactory(args)
        }
    }
}

子类实现

class ExampleVM(arguments: In) : BaseViewModel<ExampleVM.In>(arguments) {
    @Serializable
    data class In(val number: Int) : BaseViewModel.In

    companion object : BaseViewModel.ViewModelFactoryProvider<ExampleVM, In> {
        override fun createFactory(args: In): BaseViewModel.Factory<ExampleVM> {
            // 直接复用通用工厂
            return genericFactory(args)
        }
    }
}

现在可通过ExampleVM.factory(arguments)直接获取对应Factory,统一调用方式。

三、Composable路由逻辑封装

将参数解析、ViewModel创建的重复逻辑封装为通用inline函数:

inline fun <reified Route : BaseViewModel.In, reified VM : BaseViewModel<Route>> composableWithViewModel(
    crossinline content: @Composable (VM) -> Unit
) {
    composable<Route> { backStackEntry ->
        val arguments = backStackEntry.toRoute<Route>()
        val vm: VM = viewModel(
            factory = VM.factory(arguments),
            key = arguments.toString()
        )
        content(vm)
    }
}

使用示例

composableWithViewModel<ExampleVM.In, ExampleVM> { vm ->
    ExampleVMView(viewModel = vm)
}

内容的提问来源于stack exchange,提问作者Felipe Ribeiro R. Magalhaes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:34:55