摘要 Class 与 Lambda 参数

Abstract Class vs. Lambda parameters

由于 kotlin 对 lambda 的支持如此之好,我开始使用 lambda 作为 abstract 类 的构造函数参数,而不是声明 abstract val/fun

我认为它更简洁,尤其是因为 val 类型 get 是推断的。

这有什么缺点?

abstract class AbstractListScreen<T> (
    val data: Set<T>,
    val filterators: (T) -> Set<String>
) {

    fun open() {
        /* ... */
    }
}

class OrderListScreen : AbstractListScreen<Data>(data = setOf(),
                                                 filterators = { setOf(it.toString()) }
) {

    fun someEvent() {
        /* ...*/
    }
}
  1. 在您的示例中,OrderListScreen 的每个实例都将创建自己的 filterators 函数类型 (T) -> Set<String> 实例。与在编译时存储在类型定义中的抽象函数及其覆盖相比,这在内存和性能方面有额外的 运行 时间开销。
  2. 默认筛选器可以存储在 属性 中以减少此 运行 时间开销:

    class OrderListScreen : AbstractListScreen<Data>(data = setOf(),
                                                     filterators = defaultFilterators
    ) {
        companion object {
            val defaultFilterators: (Data) -> Set<String> = { setOf(it.toString()) }
        }
    
        fun someEvent() {
            /* ...*/
        }
    }
    

    但是,OrderListScreen 的每个实例仍将有其自己对 defaultFilterators 的引用,这仍然是额外的 运行 时间开销(尽管是微不足道的,除非您有许多这些类型的实例).

  3. Function types 例如 (T) -> Set<String> 可能有命名参数(例如 (element: T) -> Set<String>)但目前 IDE 如 IntelliJ IDE A 不要在生成的文档或代码存根中使用这些命名参数,因此在子类化等时此类信息会丢失。IDEs 确实在生成的文档和代码存根中使用命名参数作为抽象函数。

  4. 您不能(目前)将文档直接与您可以使用抽象函数执行的函数类型参数相关联。

当尝试考虑 运行 时间开销时,代码在使用抽象函数时看起来并没有太大不同,消除了 运行 时间开销,并且当前 IDE 改进了对生成的代码存根、文档等的支持:

abstract class AbstractListScreen<T>(val data: Set<T>) {
    abstract fun filterators(element: T): Set<String>

    fun open() {
        /* ... */
    }
}

class OrderListScreen : AbstractListScreen<Data>(data = setOf()) {
    override fun filterators(element: Data): Set<String> = setOf(element.toString())

    fun someEvent() {
        /* ...*/
    }
}