6

重写由类委托实现的接口方法时,是否可以从重写函数中调用通常委托给的类?类似于super使用继承时的调用方式。

文档中:

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // prints 10
}

请注意,覆盖按您预期的那样工作:编译器将使用您的覆盖实现而不是委托对象中的实现。

override fun print() { ... }

如何BaseImpl print()从这个被覆盖的函数中调用函数?

用例是我想向这个函数添加额外的逻辑,同时重用现有的实现。

4

5 回答 5

6

@Egor 的答案有效,并且当委托给的类作为参数传递(依赖注入)时应该是合适的。

但是,在我更具体的用例中(很抱歉在我的问题中没有明确说明),实现是直接在委托定义中定义的。

class Derived(b: Base) : Base by BaseImpl()

在这种情况下,Egor 的答案不起作用,需要更精细的方法。如果您想隐藏实现以使调用者无法修改它,可以使用以下实现。例如,在我的特定用例中,我正在创建一个聚合根并希望保护内部不变量。

open class HiddenBaseImpl internal constructor( protected val _b: Base ) : Base by _b

class Derived() : HiddenBaseImpl( BaseImpl() )
{
    override fun print()
    {
        _b.print()

        ... do something extra
    }
}

由于HiddenBaseImpl的主构造函数只能在内部使用,因此库的调用者无法实例化此类,因此被迫使用Derived. Derived现在可以在内部调用委托给的类并添加其他行为,而无需调用者传递Base.

于 2017-12-14T11:12:11.083 回答
5

由于Base是一个接口,你不能真正调用super它(类似于Java)。

相反,您需要声明b为字段并直接使用它:

class Derived(val b: Base) : Base by b {
    override fun print() {
        b.print()
        // ...
    }
}
于 2017-12-14T10:29:07.960 回答
3

您只能super在 Kotlin 中使用来访问超类,没有接口或其他奇怪的东西(请记住 - Kotlin 是在 JVM 上运行的)。但是,如果您将派生实例存储在变量中,那绝对没问题,就像Egor 在他的回答中建议的那样

为避免任何人都可以设置或检索变量,您可以使用私有(或受保护,任何适合您的用例)主构造函数并添加第二个公共构造函数:

interface Base {
    fun print()
}

class BaseImpl() : Base {
    override fun print() { print(x) }
}

class Derived private constructor(private val b : Base) : Base by b {
    constructor() : this(BaseImpl())

    override fun print() = b.print()
}

fun main(args: Array<String>) {
    val d = Derived()
    d.b // does not work, compiler error
    d.print() // prints 10
}
于 2017-12-16T03:40:07.033 回答
0

我想我有一个更好的解决方案。从某种意义上说,它更优雅,不需要额外的类,并且与批准的类完全相同。

interface Base {
    fun print()
}

class Derived private constructor (private val delegate: Base): Base by delegate {
constructor(): this(BaseImpl())

    override fun print{
      delegate.print()
    }
}
于 2020-10-16T21:20:34.157 回答
-1

您可以直接print()从属性调用函数b,但为此您需要从简单的构造函数参数更改b: Base为将参数保存为属性private val b: Base

希望这会帮助你。

于 2017-12-14T10:28:40.077 回答