Scala 中的动态继承



我有一个名为Grandparent的抽象祖父类,一个名为ParentOne的父类,以及几个名为ChildOneChildTwoChildThree、...等等。

它们编写如下:

abstract class Grandparent {
val value: Int
def print(): Unit = println(value)
}
class ParentOne extends Grandparent {
override val value: Int = 1
}
class ChildOne extends ParentOne
class ChildTwo extends ParentOne
class ChildThree extends ParentOne

我的目标是提供一种方法,用于将所有Child类中打印的value更改为例如2。我希望该方法尽可能简单。

结果就像创建一个类ParentTwo如下,并使所有类Child继承它而不是ParentOne

class ParentTwo extends Grandparent {
override val value: Int = 2
}

但我知道这是不可能的,因为我们无法动态地改变超类。我想使库的结构更好,以实现上述任务。最简单的制作方法是什么?

你写的

我的目标是提供一种改变

我将把它作为一种应该改变所有子类的值的方法,对吧?

如果是这样,您可以使用Parent类的配套对象来存储一个可以随意更改的变量

abstract class Grandparent {
def value: Int
def print(): Unit = println(value)
}
object Parent {
var mutableValue: Int = 1
}
class Parent extends Grandparent {
override def value: Int = Parent.mutableValue
}
class ChildOne extends Parent
class ChildTwo extends Parent
class ChildThree extends Parent

使用示例:

pablo-pablo@ val c = new ChildOne() 
c: ChildOne = ammonite.$sess.cmd6$ChildOne@4ad10ef2
pablo-pablo@ c.value 
res12: Int = 12
pablo-pablo@ Parent.mutableValue = 30 
pablo-pablo@ c.value 
res14: Int = 30

如果你想要一个不可变的解决方案,那么你就必须引入一个成员。目前,您使用继承注入value。但这不能在运行时更改。

一种解决方案是让子类携带值:

class ChildOne(value: Int) extends GrandParent

然后,客户端必须在每次创建对象时指定值。您可以引入构建器,因此客户端只需指定一次:

case class ChildBuilder(value: Int) {
def buildChildOne = new ChildOne(value)
def buildChildTwo = new ChildTwo(value)
}
> builder = ChildBuilder(2)
> val child1 = builder.buildChildOne
> val child2 = builder.buildChildTwo

我不知道这是否是一个可行的解决方案。不知何故,我的印象是你应该一起改变你的方法。但我不知道你想实现什么。

使用隐式参数

要求value方法通过隐式参数获取值。 客户端可以创建Environment,也可以提供可import编辑的预制环境。

请注意,实例将不拥有value。必须在每个方法调用时提供它。

case class Environment(value: Int)
trait Parent {
def value(implicit env: Environment): Int = env.value
}
class Child1 extends Parent
class Child2 extends Parent
//client code
implicit val env = Environment(2)
(new Child1).value == 2
(new Child2).value == 2

使用mixins的解决方案

trait AbstractParent{
def valueP: Int
}
trait Parent1 extends AbstractParent{
val valueP = 1
}
trait Parent2 extends AbstractParent{
val valueP = 2
}
abstract class Child1 {self: AbstractParent =>
def value = self.valueP
}
abstract class Child2 {self: AbstractParent =>
def value = self.valueP
}

//client code
val c11 = new Child1 with Parent1
val c21 = new Child2 with Parent1
val c12 = new Child1 with Parent2
val c22 = new Child2 with Parent2

最新更新