抽象类与Lambda形参



由于kotlin对lambdas有很好的支持,我开始使用lambdas作为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. 函数类型,如(T) -> Set<String>可能有命名参数(如(element: T) -> Set<String>),但目前ide,如IntelliJ IDEA不使用这些命名参数在生成的文档或代码存根,所以这些信息丢失时,子类化等。ide确实在生成的文档和抽象函数的代码存根中使用命名参数。

  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() {
        /* ...*/
    }
}

最新更新