Scala 中的动态继承

Dynamic inheritance in Scala

我有一个名为 Grandparent 的抽象三角钢琴 parent class,还有一个名为 ParentOne 的 parent class,还有几个 children class 命名为 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 class 中打印的 value 更改为例如 2。我希望该方法尽可能简单。

结果将类似于如下创建 class ParentTwo 并使所有 Child class 继承它而不是 ParentOne

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

但我知道这是不可能的,因为我们不能动态改变 superclass。我想让图书馆的结构更好,以实现上述任务。最简单的制作方法是什么?

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

一个解决方案是让 child 类 携带值:

class ChildOne(value: Int) extends GrandParent

然后客户端必须在每个 object 创建时指定值。可以引入builder,客户端只需要指定一次即可:

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

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

你写了

What I am aiming for is to provide a method for changing the

我将采用哪种方法来改变所有子 classes 的值,对吧?

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

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方法通过隐式参数获取值。 客户端可以创建 Environment,或者您可以提供可以 imported 的预制环境。

请注意,该实例不会拥有 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