【问题标题】:Polymorphic Method Return SubClass Type多态方法返回子类类型
【发布时间】:2017-02-27 23:36:16
【问题描述】:

假设我有一个包含多个子类的超类。对于这些类中的每一个,我都希望有一个 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_1(也不是我想要的抽象Super)。

我也试过把方法拉出来:

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

但这是有问题的,因为我认为您不能基于类型参数实例化一个类(因为擦除?)。

关于如何让它发挥作用有什么想法吗?

【问题讨论】:

    标签: scala oop


    【解决方案1】:

    因此您可以使用 F 有界多态性来返回正确的子类型:

    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) 
    

    这可能不合适,具体取决于您要达到的目标

    【讨论】:

    • 谢谢你,实际上我只是在打开它之前发现了 F 有界多态性。我实际上在做的是制作一个类似于tictactoe 的游戏,其中有一个人类玩家和一个计算机玩家(基础是玩家,subs 是人类和计算机)。不同的方法是makeMove(人类等待输入,计算机做出算法选择)。我也许可以通过适当的makeMove 函数逃脱
    • 这是我的 F 有界多态性解决方案 pastebin.com/zJZTmsSL
    【解决方案2】:

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

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

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

    【讨论】:

    • 我会做这样的事情吗? def updateX(newX: String): this.type = new this.type(name, newX) 我收到错误 class type expected but Super.this.type found。另外我不认为 Super 是抽象的吗?
    • 哦,对不起。现在,这行不通。您必须在每个子类中覆盖此方法,与 triggerNZ 的答案相同。这种方式只是不那么罗嗦。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多