繁体   English   中英

从基础抽象类构造子类

[英]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 Bnew 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM