程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型??

开发过程中遇到Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?的问题如何解决?下面主要结合日常开发的经验,给出你关于Kotlin 自定义简单 DI - 如何在调用实例化函数之前知道没有显式声明的类型?的解决方法建议,希望对你解决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 而不是 List,但我不确定它是否会在 find()/get() 复杂性的情况下带来任何好处,因为现在它是 O(N)对于列表,我不知道我的 KClass 的 hashCode() 是否唯一。@H_262_28@

现在我也意识到 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,请注明来意。
标签:-DI