我有一个名为Grandparent
的抽象祖父类,一个名为ParentOne
的父类,以及几个名为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
类中打印的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