Scala 中的动态继承
Dynamic inheritance in Scala
我有一个名为 Grandparent
的抽象三角钢琴 parent class,还有一个名为 ParentOne
的 parent class,还有几个 children class 命名为 ChildOne
、ChildTwo
、ChildThree
、...等等。
写法如下:
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
,或者您可以提供可以 import
ed 的预制环境。
请注意,该实例不会拥有 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
我有一个名为 Grandparent
的抽象三角钢琴 parent class,还有一个名为 ParentOne
的 parent class,还有几个 children class 命名为 ChildOne
、ChildTwo
、ChildThree
、...等等。
写法如下:
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
,或者您可以提供可以 import
ed 的预制环境。
请注意,该实例不会拥有 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