2017-07-12 184 views
0

基类斯卡拉依赖注入抽象类

abstract class BaseSourceReader[T <: BaseSource] { 

    /**                                            
    * Method to read data from source                                    
    */ 
    def readFromSource(identifier: T): Seq[String] 
} 

// Trait common to all source identifiers 
trait BaseSource 

派生类

class XYZSourceReader(param1: String) extends BaseSourceReader[XYZBaseSource] { 

    override def readFromSource(identifier: XYZBaseSource): Seq[String] = 
    // some implementation 
} 

case class XYZBaseSource(
    paramA: String, 
    paramB: Seq[String]) extends BaseSource 

现在我想要做的就是注入基础源阅读器的通用类,以便实现独立来源的:

class MySourceTrasformerJob(
    val sourceReader: BaseSourceReader[BaseSource]) { 
    // some code 
} 

并且像这样使用它:

class MyTransformerJobApp { 
    val reader = new XYZSourceReader(param) 
    val job = MySourceTrasformerJob(reader) 
} 

对于此代码段工作时,编译器提示class SourceReader is invariant in type T. You may wish to define T as +T instead. (SLS 4.5)

我试图更新BaseSourceReader

- abstract class BaseSourceReader[T <: BaseSource] { + abstract class BaseSourceReader[+T <: BaseSource] {

但这导致与readFromSource方法错误的错误:协变型T在价值标识符的类型T中发生在逆变位置。

一个可行的解决方案,我发现被捆绑实施的源代码,但它不是“通用”,足以实现:

class MySourceTrasformerJob(
    val sourceReader: BaseSourceReader[XYZBaseSource]) { 
    // some code 
} 

我有点陷在这个循环和尝试模型更新,任何建议的方式来处理这个,但绝对坚持通用抽象类依赖注入?

回答

2

如果你有一个既需要同时又不是协变(或逆向)的类型(这是不可能实现的,在这种情况下你所能做的就是让它离开它不变),您可以通过重新编写MySourceTransformerJob这样可以避免这一点:

case class MySourceTransformerJob[T <: BaseSource](sourceReader: BaseSourceReader[T]) 

我这样做,并没有进一步的修改你的代码编译。 这也是表达你意图的更自然的方式。毕竟你正在设计你的BaseSourceReader[T <: BaseSource]T类型的通用下限。所以MySourceTransformerJob最好在T上询问相同的要求,如果它不是通过设计来限制它自己的话。

+2

看看为什么这是必须的:考虑如果一个'BaseSource'的实例而不是'XYZBaseSource'的实例被传入'MySourceTrasformerJob'的'sourceReader'的'readFromSource'方法会发生什么。你的原始类型表明应该是可能的,但是'XYZSourceReader'不能从那个实例读取。 –