当覆盖class delegation实现的接口方法时,是否可以从覆盖函数中调用通常委托给的类?与使用继承时调用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()
函数?
用例是我想在重用现有实现的同时为此函数添加额外的逻辑。
答案 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
的主要构造函数只能在内部使用,因此库的调用者无法实例化此类,因此不得不使用Derived
。 Derived
现在可以调用委托给内部的类,并添加其他行为,而不允许调用者传递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}}
希望这会对你有所帮助。