2017-07-12 246 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'不能從那個實例讀取。 –