1

如果我有一个接收 aCallback作为参数的函数,我如何使用子类/派生类的“集合”或“组”调用此函数,Callback以便根据接收到的参数,我可以启用/禁用如果收到子类/派生类“具有”或“匹配”功能,则某些功能?

例如

import kotlin.random.Random

interface Callback

interface FruitsCallback : Callback {
    fun onFruitsDeleted(ignored: Int)
}

interface VegetablesCallback : Callback {
    fun onVegetablesDeleted(ignored: Int)
}

class FruitsStore : FruitsCallback {

    override fun onFruitsDeleted(ignored: Int) {
        throw NotImplementedError()
    }
}

class VegetablesStore : VegetablesCallback {

    override fun onVegetablesDeleted(ignored: Int) {
        throw NotImplementedError()
    }
}

fun delete(callback: Callback) {

    if (callback is FruitsCallback) {
        // Delete 5 fruits
        callback.onFruitsDeleted(5)
    }

    if (callback is VegetablesCallback) {
        // Delete 7 vegetables
        callback.onVegetablesDeleted(7)
    }
}

fun main() {

    val fruitsStore = FruitsStore()
    val vegetablesStore = VegetablesStore()

    val callback: Callback = if (Random.nextBoolean()) {
        fruitsStore + vegetablesStore
    } else fruitsStore

    delete(callback)
}

main()当我尝试执行时,错误出现在方法中fruitsStore + vegetablesStore。这显示了类型不匹配问题。关于 kotlin 的一些事情.plus()

但是,我如何在使用时将以下类型添加在一起coroutines

val exceptionHandler = CoroutineExceptionHandler { context, throwable -> println("$throwable") }
val coroutineContext = Dispatchers.Main + SupervisorJob() + exceptionHandler

我想知道如何coroutineContext能够接收一组这些类型的实例并将它们表示为一个。

我对科特林相当陌生。请解释:

  • 为什么我做不到?
  • 为什么协程可以做到?
  • 这个叫什么?
  • 在上面的例子中我怎么能做到这一点?
4

1 回答 1

3

协程 API 使用运算符重载来使+运算符执行通常无法执行的操作。如果查看源代码,重载的 plus 运算符的函数会实例化一个新的 CoroutineContext,该 CoroutineContext 复制了两个操作数的属性值。

在您的情况下,要完成这项工作,您必须编写自己的运算符函数。但是尝试有条件地实现多个接口很快就会变得非常复杂。在您的示例中,只有两种可能的回调类型,并且已经形成了具有三个分支的长函数:

operator fun Callback.plus(other: Callback): Callback {
    val callbacks = listOf(this, other)
    return when {
        callbacks.all { it is FruitsCallback } -> object: FruitsCallback {
                override fun onFruitsDeleted(ignored: Int) {
                    callbacks.forEach { (it as FruitsCallback).onFruitsDeleted(ignored) }
                }
            }

        callbacks.all { it is VegetablesCallback } -> object : VegetablesCallback {
                override fun onVegetablesDeleted(ignored: Int) {
                    callbacks.forEach { (it as VegetablesCallback).onVegetablesDeleted(ignored) }
                }
            }

        else -> object: FruitsCallback, VegetablesCallback {
            override fun onFruitsDeleted(ignored: Int) {
                callbacks.forEach { (it as? FruitsCallback)?.onFruitsDeleted(ignored) }
            }

            override fun onVegetablesDeleted(ignored: Int) {
                callbacks.forEach { (it as? VegetablesCallback)?.onVegetablesDeleted(ignored) }
            }
        }
    }
}

如果有回调的第三个实现,上述函数将有七个分支。如果您添加额外的实现,这里没有强制您记得更新此功能。

也就是说,您delete()使用的函数版本is是代码异味,未能利用多态性。在这种情况下,最好将其添加delete()为一个函数,Callback并且每个实现都可以自己定义它的含义。

于 2020-03-12T14:26:03.720 回答