大佬教程收集整理的这篇文章主要介绍了Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我目前正在学习 Kotlin 并制作不同的东西以应对旅途中的问题。
现在我对示例项目有简单的 DI 实现 - 有效 - 但我对实现有疑问,因为用法与 Koin 不同(我想他们做得更好)。
在我的 DI 中,我将模块提供为 List,其中 Item 是由 Single 和 Factory 类实现的接口。它需要 KClass 和构造函数的工厂方法。这使得模块声明看起来像这样:
val module: List<Item> = listof(
Factory(DatabaseKernel::class) { KernelNative() }
)
Koin 模块如下所示:
private val model = module()
{
factory<Gson> { Gson() }
}
我知道在 Koin 的情况下 factory() 是一个内联函数。但是,我不明白使用函数而不是对象的选择。我想这可能是为了我不需要的附加功能。
重点是我实际上不必为上面的示例指定类型,只需提供 factory { Gson() }
。在我的实现中,除非我调用构造函数,否则我不知道对象的类型,这是不需要的,因为它只会为模块中的每个 Item 创建一个实例。但我需要知道查找类型。
我在 Koin 的阅读类型中缺少什么?它实际上实例化了模块中的每个对象吗?因为我想尽可能使用惰性。
另一个问题太宽泛了,但欢迎回答——除了我遇到的那个问题之外,我还缺少什么?也许在实施最佳实践中。现在我认为我可能可以使用 Map
现在我也意识到 Map 实现消除了任何不指定类型的希望。
示例用法:
val foo: DatabaseKernel by inject()
Bellow 是一个完整的实现列表:
internal object Inject
{
val module: List<Item> = listof(
Factory(DatabaseKernel::class) { KernelNative() }
)
inline fun <reifIEd T: Any> inject(): Lazy<T> =
lazy { module.find { it.type == T::class }?.get() as? T ?: error("Class ${T::class} not specifIEd") }
interface Item
{
val type: KClass<out Any>
val construct: () -> Any
fun get(): Any
}
private data class Single(overrIDe val type: KClass<out Any>,overrIDe val construct: () -> Any) : Item
{
private val instance: Any by lazy(construct)
overrIDe fun get(): Any = instance
}
private data class Factory(overrIDe val type: KClass<out Any>,overrIDe val construct: () -> Any) : Item
{
overrIDe fun get(): Any = construct()
}
}
这里是 Map 的实现:
internal object FMPInject
{
val module: Map<KClass<out Any>,Item> = mapOf(
DatabaseKernel::class to Factory { KernelNative() }
)
inline fun <reifIEd T: Any> inject(): Lazy<T> =
lazy { module[T::class]?.get() as? T ?: error("Class ${T::class} not specifIEd") }
interface Item
{
val construct: () -> Any
fun get(): Any
}
private data class Single(overrIDe val construct: () -> Any) : Item
{
private val instance: Any by lazy(construct)
overrIDe fun get(): Any = instance
}
private data class Factory(overrIDe val construct: () -> Any) : Item
{
overrIDe fun get(): Any = construct()
}
}
解决方案:
正如@Joffrey 指出的那样,我可以使用 reifIEd factory() 和 single() 函数来推断类型而无需明确指定它。 Bellow 是它如何工作的完整示例(带列表)。
internal object FMPInject
{
val module: List<Item> = listof(
factory<DatabaseKernel> { KernelNative },// explicit interface type
factory { Gson() } // infers from constructor function
)
inline fun <reifIEd T: Any> inject(): Lazy<T> =
lazy { module.find { it.type == T::class }?.get() as? T ?: error("Class ${T::class} not specifIEd") }
private inline fun <reifIEd T: Any> factory(noinline constructor: () -> T) = Factory(T::class,constructor)
private inline fun <reifIEd T: Any> single(noinline constructor: () -> T) = Single(T::class,constructor)
interface Item
{
val type: KClass<out Any>
val construct: () -> Any
fun get(): Any
}
private data class Single(overrIDe val type: KClass<out Any>,overrIDe val construct: () -> Any) : Item
{
overrIDe fun get(): Any = construct()
}
}
我还发现 Koin 使用 Set 进行存储,它提供了唯一/覆盖功能。
我知道在 Koin 的情况下 factory() 是一个内联函数。但是,我不明白使用函数而不是对象的选择。我想这可能是为了我不需要的附加功能。
正如您所指出的,factory
函数是一个 inline
函数,它允许使用 reified
类型参数,这正是您不需要传递的原因一个 KClass
显式(函数可以从具体化的类型参数中获取它)。
在我的实现中,除非我调用构造函数,否则我不知道对象的类型,这是不需要的,因为它只会为模块中的每个项目创建一个实例。但我需要知道查找类型。
您不需要计算表达式(在本例中为构造函数)来了解其类型。如果您使用带有类型参数 T
的泛型函数,则可以从作为参数传递的表达式推断出 T
。
结合上面的 2 条语句,你可以这样声明:
inline fun <reified T: Any> factory(constructor: () -> T) = Factory(T::class,constructor)
请注意,这只是关于您的 DI 的外部 API,您可以(并且可能会)在您的实现中依赖内部的 KClass
。
以上是大佬教程为你收集整理的Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?全部内容,希望文章能够帮你解决Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。