ListBuffer中的协方差/子类型[BaseType]

时间:2015-07-15 19:14:08

标签: java scala

我有三个类都实现了模拟功能,但细节上有所不同。我想创建一个抽象基类并移动共享的代码。现在我被卡住了。

每个子类都有一个ListBuffer,它包含另一个关系的对象,即某个基本类型的子类。更具体地说:

trait data {
  def parseXML();
}

trait ConcreteDataA extends Data {
  override def parseXML(): Unit = {...}
}

abstract class Worker {
   protected var data: ListBuffer[Data] = _

   def loadXML(): Unit = {
     val path: String = getPath()
     ... // Parse XML-file at path and put data into data-ListBuffer 
   }

   def getPath(): String;
}

object ConcreteWorkerA extends Worker {
  data = new ListBuffer[ConcreteDataA] // Here the expected type differs

  override def getPath(): String = {
    return "pathTo/ConcreteWorkerA/s/WorkingPlace"
  }
}

我不确定如何最好地解决这个问题并感谢任何输入

2 个答案:

答案 0 :(得分:3)

您可以将通配符类型用于通用参数:ListBuffer[_ <: Data]。您还可以使用参数T <: Data创建整个类/特征泛型,然后将变量声明为ListBuffer[T]

您还应该考虑为什么要在这里使用抽象类。您可以阅读here关于抽象类相对于特征的(极少数)优点。您可能还会重新考虑为什么data被声明为var,以及为什么在Worker中实例化它。您可以像这样重建您的类型:

trait Worker[T <: Data]
{
   protected val data: ListBuffer[T] //Not var, and uninstantiated
   def loadXML: Unit = ???
   def getPath: String
}

object ConcreteWorkerA extends Worker[ConcreteDataA]
{
  override val data = new ListBuffer[ConcreteDataA] // Here the expected type differs
  override def getPath: String = "foo"
}

答案 1 :(得分:3)

我的第一个猜测是抽象类型成员:

abstract class Worker {
  type DataType <: Data

  protected var data: ListBuffer[DataType] = _
}

object ConcreteWorkerA extends Worker {
  type DataType = ConcreteDataA

  data = new ListBuffer[ConcreteDataA]
}

但是,为什么data甚至在Worker中宣布?它缺少_的初始化也是一种代码味道。你至少可以将它声明为一个抽象的val:

abstract class Worker {
  type DataType <: Data

  protected val data: ListBuffer[DataType]
}

object ConcreteWorkerA extends Worker {
  type DataType = ConcreteDataA

  protected val data = new ListBuffer[ConcreteDataA]
}