我有三个类都实现了模拟功能,但细节上有所不同。我想创建一个抽象基类并移动共享的代码。现在我被卡住了。
每个子类都有一个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"
}
}
我不确定如何最好地解决这个问题并感谢任何输入
答案 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]
}