【发布时间】:2021-10-25 10:12:55
【问题描述】:
我正在寻找一种方法将配置输入传递给从基类派生的工厂,并根据该工厂的派生类保存不同的输入参数。
我正在努力寻找实现这一点的好方法。所以让我展示一下我目前的情况以及问题出在哪里:
class ExampleFragmentFactoryImpl @Inject constructor(
private val providers: List<ExampleFragmentProvider<out ExampleInput>>
): ExampleFragmentFactory {
@Suppress("UNCHECKED_CAST")
override suspend fun <T: ExampleInput> create(
pageType: T
): Fragment {
providers.forEach { provider ->
try {
val typesafeProvider = provider as? ExampleFragmentProvider<T>
typesafeProvider?.let {
return it.provide(pageType)
}
} catch (e: ClassCastException) {
// This try-except-block shall be avoided.
}
}
throw IllegalStateException("could not create Fragment for pageType=$pageType")
}
}
这里是工厂界面...
interface ExampleFragmentFactory {
suspend fun <T : ExampleInput> create(
pageType: T
): Fragment
}
现在提供者接口...
interface ExampleFragmentProvider<T: ExampleInput> {
suspend fun provide(
pageType: T
) : Fragment
}
输入类...
sealed class ExampleInput {
object NotFound : ExampleInput()
object WebView : ExampleInput()
data class Homepage(
val pageId: String
) : ExampleInput()
}
最后是提供者实现:
internal class ExampleHomepageProvider @Inject constructor() :
ExampleFragmentProvider<ExampleInput.Homepage> {
override suspend fun provide(pageType: ExampleInput.Homepage): Fragment {
TODO()
}
}
如上所述,在工厂中需要 try-except 真的很糟糕。应该有很好的方法来实现这一点而无需尝试除外。不幸的是,由于类型擦除,无法在转换之前检查类型。使用多态代码无法使用具体类型 afaik。
另一种可能的解决方案是避免使用泛型并在提供程序provide() 方法中强制转换为所需的输入类型——但这也不是很好。
你有什么建议我可以改进这种工厂吗?
【问题讨论】:
-
只是为了确保我做对了:
ExampleFragmentFactory应该与不同类型的T一起工作,它拥有各种T类型的提供者,当我们调用create(MyExampleInputType)时它应该搜索与此类型相关的提供商,对吗?我认为如果不存储Class/KClass/KType的提供者,这是不可能的。您可以创建一个属性,如:val ExampleFragmentProvider.pageType: KType或使用 reified 函数将提供程序添加到工厂(但我看到它是注入的,所以可能不可能)。也许有更好的方法。 -
是的,您的要求是正确的——是的,我想注入可用的提供程序。关于您的方法的问题:如何使用提供程序类获取 KType 实例?
标签: kotlin generics factory reification