在覆盖内使用类委派时调用(基本)委派函数

时间:2017-12-14 10:23:07

标签: kotlin kotlin-delegate

当覆盖class delegation实现的接口方法时,是否可以从覆盖函数中调用通常委托给的类?与使用继承时调用super的方式类似。

来自documentation

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()函数?

用例是我想在重用现有实现的同时为此函数添加额外的逻辑。

5 个答案:

答案 0 :(得分:4)

由于Base是一个接口,因此您无法在其上调用super(类似于Java)。

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

class Derived(val b: Base) : Base by b {
    override fun print() {
        b.print()
        // ...
    }
}

答案 1 :(得分:4)

@Egor's answer works并且在委托给的类作为参数传递(依赖注入)时应该是合适的。

但是,在我更具体的用例中(道歉没有明确in my question),实现直接在委托定义中定义。

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

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

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的主要构造函数只能在内部使用,因此库的调用者无法实例化此类,因此不得不使用DerivedDerived现在可以调用委托给内部的类,并添加其他行为,而不允许调用者传递Base的不同实现。

答案 2 :(得分:1)

你只能在Kotlin中使用super来访问超类,没有接口或其他奇怪的东西(记住--Kotlin在JVM上运行)。但是,如果将deriate实例存储在变量中,如Egor suggested in his answer

,则绝对没问题

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

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
}

答案 3 :(得分:0)

我认为我对此有更好的解决方案。 从某种意义上讲,它更优雅,因为它不需要额外的类,并且它与批准的类完全相同。

interface Base {
    fun print()
}

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

    override fun print{
      delegate.print()
    }
}

答案 4 :(得分:-1)

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

希望这会对你有所帮助。