多态方法返回子类类型

时间:2017-02-27 23:36:16

标签: scala oop

假设我有一个包含多个子类的超类。对于这些类中的每一个,我希望有一个updatePropertyX方法来更新属性x并返回该类的新实例。

此外,我希望超类是抽象的,我想只实现一次这个updatePropertyX方法。

这是我到目前为止所尝试的内容:

class Super(val name: String, val x: String)
{
    def identify = println("This is a Super with properties" +
        s"\n\tName: ${this.name}\n\tData: ${this.x}")

    def updateX(newX: String): Super = new Super(name, newX)
}

class Sub_1(name: String, x: String) extends Super(name, x)
{
    override def identify = println("This is a Sub_1 with properties" +
            s"\n\tName: ${this.name}\n\tData: ${this.x}")
}

class Sub_2(name: String, x: String) extends Super(name, x)
{
    override def identify = println("This is a Sub_2 with properties" +
            s"\n\tName: ${this.name}\n\tData: ${this.x}")
}

val s1 = new Sub_1("sub1", "original data")
s1.identify

/*
This is a Sub_1 with properties
    Name: sub1
    Data: original data
*/

val s2: Sub_1 = s1.updateX("new data")

但最后一行有一个类型不匹配错误:找到Super,预期Sub_1Super也不是我想要的抽象。)

我也试过把方法拉出来:

def updateSubX[T <: Super](orig: T, newX: String): T = new T(orig.name, newX)
val s2 = updateSubX(s1, "new data")

但这是有问题的,因为我不认为你可以根据类型参数实例化一个类(因为擦除?)。

有关如何让它发挥作用的任何想法?

2 个答案:

答案 0 :(得分:2)

所以你可以使用F-bounded多态来返回正确的子类型:

abstract class Super[A <: Super[A]](val name: String, val x: String) {
    abstract def updateX(newX: String): A
}

类型很奇怪,但是它可以完成任务。

现在您的子类看起来像:

class Sub_1(name: String, x: String) extends Super[Sub_1](name, x)

不幸的是,在不知道子类的构造函数的情况下,你实际上不能实际实现updateX方法,并且必须将它抽象为子类来实现,这很尴尬(至少它是强制执行的)。由于构造函数可以采用不同的参数,我没有看到另一种(非反射)方式。

更广泛的问题是:你想用这个来实现什么目标?如果所有子类都包含相同的不可变数据,那么有什么不同?

如果它只是行为(如在你的identify方法中),那么删除继承并且只有一个带有标识的类作为函数传入而不是工作吗?类似的东西:

class MyClass(val name: String, val x: String, val identify: () => Unit) 

这可能不合适,取决于你想要实现的目标

答案 1 :(得分:0)

您可以使用this.type作为返回类型。

def updateX(newX: String) : this.type = ...

这将返回继承方法的确切类型,直到任何其他实现的特征。