gpt4 book ai didi

kotlin - 以多态方式处理大量相似的单态类

转载 作者:行者123 更新时间:2023-12-02 13:34:47 24 4
gpt4 key购买 nike

我有一个库,可以生成一大堆看起来非常相似的 Java 类。为简洁起见,让我们在 Kotlin 中指定类似的内容:

data class A(val commonParam1: String, val commonParam2: String, val specialParam: Int)
data class B(val commonParam1: String, val commonParam2: String, val specialParam: String)
data class C(val commonParam1: String, val commonParam2: String, val specialParam: Boolean)
data class D(val commonParam1: String, val commonParam2: String, val specialParam: Float)

显然,最好生成单个泛型类或接口(interface):
data class G<T>(val commonParam1: String, val commonParam2: String, val specialParam: T)

但是该库不会生成那种代码。我有几十个这样的类,它们在不同的地方生成,所以这是一个 m×n 的情况。不幸的是,这些类不共享一个通用接口(interface)(我可以使用)。所以在我看来,有五个选项可以解决这个问题:
  • 编写所有可与任何生成的类一起工作的代码 m×n 次。这是一大堆重复,但一点也不复杂,而且很安全
  • 使用反射。首先生成这些类的想法是提高类型安全性。反射会再次把它扔出窗外,所以感觉适得其反
  • 为我自己的代码使用代码生成。感觉有点重手的方法,我的团队没有代码生成经验
  • 使用 ArrowKT typeclasses . Extension Interfaces会很棒,但我可能会使用当前存在的黑客。我仍然需要提供很多样板,因为我必须为这些类中的每一个提供我的接口(interface)的证据
  • 使用 Arrow-Meta quasi-quoter,但我认为我不应该在生产中使用 Arrow-Meta

  • 我还有其他选择吗?有没有办法抽象出类似的类?

    在这个具体案例中,我的 Graphql 模式有很多突变,其中 MutationInputs这些都非常相似。我们不直接控制模式的形状。由于每个突变也有自己的输入和输出类型,即使我大量使用片段,构建这些突变并解释它们的输出也是一件苦差事,因为即使是提取片段的代码也必须重复。

    这在 Graphql 中通常不是问题,因为大部分是在 JS 或 TS 中完成的,两者都有鸭子类型。 Kotlin 没有鸭子类型。

    最佳答案

    我在这里列出了多个选项,其中一些可能会组合使用以重用代码并生成最少数量的繁琐代码。

    具有默认实现的接口(interface)

    您可以使用具有默认函数实现的接口(interface)来提供公共(public)基础:

    interface CommonDataInterface<T> {
    val commonParam1: String
    val commonParam2: String
    val specialParam: T

    fun foo() { ...implementation here }
    fun bar() { ...implementation here }
    fun zoo(x: T): T { ...implementation here }
    }

    // concrete variations, using common interface functions implemented above:

    data class A(override val commonParam1: String,
    override val commonParam2: String,
    override val specialParam: Int)
    : CommonDataInterface<Int>
    data class B(override val commonParam1: String,
    override val commonParam2: String,
    override val specialParam: String)
    : CommonDataInterface<String>
    data class C(override val commonParam1: String,
    override val commonParam2: String,
    override val specialParam: Boolean)
    : CommonDataInterface<Boolean>
    data class D(override val commonParam1: String,
    override val commonParam2: String,
    override val specialParam: Float)
    : CommonDataInterface<Float>

    使用非数据类扩展基类

    另一种方法是不是数据类的泛型类:
    class G<T>(val commonParam1: String, val commonParam2: String, val specialParam: T) { 
    fun foo() { ...implementation here }
    fun bar() { ...implementation here }
    fun zoo(x: T): T { ...implementation here }
    }

    // concrete variations, using common functions from base class

    class A(commonParam1: String, commonParam2: String, specialParam: Int)
    : G<Int>(commonParam1, commonParam2, specialParam)
    class B(commonParam1: String, commonParam2: String, specialParam: String)
    : G<String>(commonParam1, commonParam2, specialParam)
    class C(commonParam1: String, commonParam2: String, specialParam: Boolean)
    : G<Boolean>(commonParam1, commonParam2, specialParam)
    class D(commonParam1: String, commonParam2: String, specialParam: Float)
    : G<Float>(commonParam1, commonParam2)

    这并没有节省多少打字,而且有很多冗余参数。

    使用接口(interface)的透明委托(delegate)

    如果您需要将所有内容保留在类中或想要组合多个不同的功能集(您可以实现多个接口(interface)并委托(delegate)给多个支持实现),则另一种方法是使用“委托(delegate)继承”:
    interface CommonDataInterface {
    val commonParam1: String
    val commonParam2: String

    fun foo()
    fun bar()
    }

    data class CommonData(override val commonParam1: String,
    override val commonParam2: String)
    : CommonDataInterface {
    override fun foo() { ...implementation here }
    override fun bar() { ...implementation here }
    }

    // concrete implementations using common functions via automatic delegation

    data class A(private val common: CommonDataInterface,
    val specialParam: Int) : CommonDataInterface by common {
    fun zoo(x: Int): Int { ...implementation here using specialParam }
    }

    data class B(private val common: CommonDataInterface,
    val specialParam: String) : CommonDataInterface by common {
    fun other(y: String): String { ...implementation here using specialParam }
    }

    data class C(private val common: CommonDataInterface,
    val specialParam: Boolean) : CommonDataInterface by common

    data class D(private val common: CommonDataInterface,
    val specialParam: Float) : CommonDataInterface by common

    但以上不允许 specialParam由任何通用功能使用,并且将按特化实现。

    使用注释处理器生成类的排列

    您可以编写自己的注释处理器,这是代码生成或其他编译时操作的一种形式,将注释添加到您的特殊类并让注释处理器生成字节码中的所有排列。然后它可以融入到你的编译过程中,神奇地出现那些额外的类。

    您需要在某处查看 Kotlin 如何进行注释处理和一般主题。此外,Kotlin 1.4 之后可能会是一个编译器插件 API,它可以帮助编写做类似工作的插件。

    注释处理的一些链接表明它并不难使用:
  • KAPT - Kotlin annotation processor
  • Hello World of annotation processing in Kotlin
  • Idiomatic Kotlin - annotation processor and code generation
  • MerryAnnotation - your first annotation processor in Kotlin Android


  • 使用 Kotlin 的代码生成库生成 Kotlin 代码

    查看 Kotlin 代码生成的一个简单方法是 KotlinPoet图书馆。它是一种生成代码的编程方式,即使对于代码生成经验很少的团队来说也很容易。这可以与前面提到的关于如何构建类的变体一起使用。它也可以与注释处理一起使用,作为在编译期间触发代码生成的方法。

    关于kotlin - 以多态方式处理大量相似的单态类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59197837/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com