我希望有一个特点,可以a)用特定的方法混合到任何类中,并且b)可以调用super。像这样:
// A and B are from a library that I don't control. No changes allowed here.
class A {
def stuff = "a stuff"
}
class B {
def stuff = "b stuff"
}
// My code starts here
type HasStuffMethod = {
def stuff: String
}
// Note that this doesn't compile - gets:
// class type required but AnyRef{def stuff: String} found
trait ImplementsStuff extends HasStuffMethod {
override def stuff = "trait + " + super.stuff
}
val a = new A with ImplementsStuff
assert(a.stuff == "trait + a stuff")
val b = new B with ImplementsStuff
assert(b.stuff == "trait + b stuff")
有没有办法做到这一点?
请注意,我不控制A和B;他们来自另一个我无法修改的图书馆。
[编辑 - 看到答案后添加]
有没有办法以这样的方式调用原始方法?
trait ImplementsStuff {
this: HasStuffMethod =>
abstract override def stuff = "foo" + "how do I call the original method here?"
}
这没用,因为当你把它混合成它给出的东西时:
错误:在类A =>的A类中覆盖方法内容java.lang.String中; 特征中的方法东西类型=>的ImplementsStuff java.lang.String中 如果没有第三个成员,则不能覆盖具体成员 被两者所覆盖(这条规则旨在防止“意外” 覆盖 '')
但这不是偶然的;是的,我真的希望你完全采用现有的方法。然后让我也称之为。
答案 0 :(得分:5)
我可以想到两个选择:
选项1,使用自我类型注释并从新方法(我想象地称为stuff
)调用callStuff
而不是覆盖它。
trait ImplementsStuff {
this: HasStuffMethod =>
def callStuff = "trait + " + this.stuff
}
val a = new A with ImplementsStuff
assert(a.callStuff == "trait + a stuff")
val b = new B with ImplementsStuff
assert(b.callStuff == "trait + b stuff")
选项2(因为你说你不控制A和B)是亲爱的旧装饰模式。
trait HasStuff { def stuff: String }
class DecorateStuff(decorated: HasStuffMethod) extends HasStuff {
def stuff = "trait + " + decorated.stuff
}
val decA = new DecorateStuff(new A)
assert(decA.stuff == "trait + a stuff")
val decB = new DecorateStuff(new B)
assert(decB.stuff == "trait + b stuff")
答案 1 :(得分:4)
在这种情况下你需要abstract override
。
答案 2 :(得分:1)
没有办法在Scala中扩展精炼类型(我不确定这可以安全地拉出来,但探索它会很有趣)。
我有一个更详细的解决方案,但让你更接近你的目标。
trait HasStuff {
def theirStuff: String
}
trait ImplementsStuff extends HasStuff {
def stuff = "trait + " + theirStuff
}
请注意,我没有精炼类型,而是具有特征,并在实现中扩展它。我需要手动添加超级访问者,我通过委托来做。 HasStuff
定义了它们,我在mixin网站上实现它们:
val a = new A with ImplementsStuff {
def theirStuff = super[A].stuff
override def stuff = super[ImplementsStuff].stuff
}
val b = new B with ImplementsStuff {
def theirStuff = super[B].stuff
override def stuff = super[ImplementsStuff].stuff
}
在mixin站点,我需要实现超级访问器(theirStuff
)以转发到正确的继承方法。我还需要在此级别覆盖stuff
,因为ImplementsStuff
不会继承stuff
方法,因此它不能override
。
在stuff
和a
上拨打b
表示已被覆盖:
$ a.stuff
res0: java.lang.String = trait + a stuff
$ b.stuff
res1: java.lang.String = trait + b stuff