2015-07-15 3 views
1

У меня есть три класса, которые реализуют функции аналогов, но отличаются тонкой детализацией. Я хотел создать абстрактный базовый класс и переместить общий код. Теперь я застрял.Covariance/SubType в ListBuffer [BaseType]

В каждом подклассе есть 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" 
    } 
} 

Я не уверен, как лучше решить эту проблему и благодарны за любой вклад

ответ

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" 
} 
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? Его отсутствие инициализации с _ также является запахом кода. Вы могли бы хотя бы объявить его абстрактным:

abstract class Worker { 
    type DataType <: Data 

    protected val data: ListBuffer[DataType] 
} 

object ConcreteWorkerA extends Worker { 
    type DataType = ConcreteDataA 

    protected val data = new ListBuffer[ConcreteDataA] 
} 
Смежные вопросы