[英]Constructing subclasses from base abstract class
我想在抽象类中定义一个构造函数,它将创建具体的子类。
abstract class A {
type Impl <: A
def construct() : Impl = {
val res = new Impl() //compile error: class type required but A.this.Impl found
// do more initialization with res
}
}
class B extends A {type Impl = B}
class C extends A {type Impl = C}
//...
val b = new B
b.construct() // this should create a new instance of B
这有什么不对? 这甚至可以实现吗? 编辑:澄清:我想抽象构造方法。 我不想从子类或伴随对象中单独调用new B
和new C
如果要创建新实例,则需要显式调用构造函数。
abstract class A {
def newInstance(): this.type;
def construct() : this.type = {
val res = newInstance()
}
}
class B extends A {
def newInstance() = new B()
}
Scala在运行时擦除类型,因此在创建类时无法知道Impl的含义。
您可以将构造函数放在伴随对象中,而不是在抽象类中。 像这样:
object A {
def apply(i:Int):A = new B(...)
def apply(s:String):A = new C(...)
}
现在,您可以通过调用A(42)
或A("foobar")
来创建A
的实例。 当然,字符串和整数参数仅是示例。 如果所有构造函数的参数具有相同的类型,则此重载将不起作用。 在这种情况下,您可以轻松创建不同的方法,并将其称为除apply
其他方法。
您可以使用反射来创建新实例。 像这样的东西会起作用,但在我看来并不值得。 首先,您只能检查运行时是否存在合适的构造函数。
def newInstance[T:ClassManifest]:T = {
val klass = implicitly[ClassManifest[T]].erasure
val constr = klass.getConstructors()(0)
constr.newInstance().asInstanceOf[T]
}
abstract class A {
def construct(implicit cm:ClassManifest[this.type]): this.type = {
val res = newInstance[this.type]
res
}
}
class B extends A
我的评论留在Monkey
回应。 解决此问题的一种方法是使用奇怪的重复模板模式 (CRTP)和自我类型:
abstract class A[T <: A[T]] { this: T =>
def newInstance(): T;
def construct(): T = {
val res = newInstance()
res
}
def some(): T = this
}
class B extends A[B] {
def newInstance() = new B()
}
也许有一个更好的解决方案,但这是我发现的迄今为止。
看起来这是不可能的。 根据Scala的书(由Oderski,Spoon,Venners), 您无法创建抽象类型的实例 。 请参阅:摘要类型章节,货币案例研究。 稍后可以使用“虚拟类”来支持此功能。
我提出以下模式:
abstract class A($params) {
// do common initialisation here
def construct() : A
def foo(...) = {
...
val bar = construct()
...
}
}
class B($moreparams) extends A($someparams) {
// do special initialisation here
def construct() = new B()
}
你现在拥有的所有减少量恰好是每个子类一行。 我认为这是一个很小的代价,以支付a)一个工作解决方案,b)不使用反射(这基本上打破了静态类型系统为您提供的所有保证)。
我仍然很好奇为什么你需要在A
里面construct
。 闻起来很腥。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.