2016-09-25 94 views
2

假設我有以下的特徵定義的接口,並需要幾個類型參數...使用apply方法的泛型類型的Scala工廠?

trait Foo[A, B] { 

    // implementation details not important 

} 

我想使用的同伴對象的一個​​工廠性狀的具體實現。我也想強迫用戶使用Foo接口,而不是子類所以我躲在同伴對象的具體實現,像這樣:

object Foo { 

    def apply[A, B](thing: Thing): Foo[A, B] = { 
    ??? 
    } 

    private case class FooImpl[A1, B1](thing: Thing) extends Foo[A1, B1] 

    private case class AnotherFooImpl[A2, B1](thing: Thing) extends Foo[A2, B1] 

} 

我希望能夠使用工廠如下:

val foo = Foo[A1, B1](thing) // should be an instance of FooImpl 

val anotherFoo = Foo[A2, B1](thing) // should be an instance of AnotherFooImpl 

如何實現apply方法來做到這一點?這SO post似乎接近標記。

+0

什麼是'A1'和'A2'之間的關係?遺產?沒有關係? –

回答

0

使用TypeTags(爲了克服類型參數的擦除),我們可以根據傳入apply方法的類型參數調用相應的隱藏實現,如下所示。它正確地實例化相應的實施方案,而是爲Foo類型信息丟失,實際上它的未來的一些垃圾一樣_202等?我不知道爲什麼會發生這種情況,以及如何保留Foo的正確類型。也許有人可以拋開這一點。

trait Foo[A,B] 
object Foo { 
    def apply[A: TypeTag, B: TypeTag](thing: Thing) = 
    if(typeTag[A] == typeTag[Int]) 
     FooImpl(thing) 
    else if(typeTag[A] == typeTag[String]) 
     AnotherFooImpl(thing) 
    else 
     new Foo[Double,Double] {} 

    private case class FooImpl(thing: Thing) extends Foo[Int, String] 
    private case class AnotherFooImpl(thing: Thing) extends Foo[String, String] 
    } 

Foo[Int,String](new Thing) // Foo[_202, _203] = FooImpl([email protected]) 

The actual types for _203 and _203 are: ??? 
// type _203 >: String with _201, type _202 >: Int with _200 


Foo[String,String](new Thing) //Foo[_202, _203] = AnotherFooImpl([email protected]) 
3

如何:

trait Foo[A, B] 
trait Factory[A, B] { 
    def make(thing: Thing): Foo[A, B] 
} 

class Thing 

object Foo { 
def apply[A, B](thing: Thing)(implicit ev: Factory[A, B]) = ev.make(thing) 

private case class FooImpl[A, B](thing: Thing) extends Foo[A, B] 
private case class AnotherFooImpl[A, B](thing: Thing) extends Foo[A, B] 

implicit val fooImplFactory: Factory[Int, String] = new Factory[Int, String] { 
    override def make(thing: Thing): Foo[Int, String] = new FooImpl[Int, String](thing) 
} 

implicit val anotherFooImplFactory: Factory[String, String] = new Factory[String, String] { 
    override def make(thing: Thing): Foo[String, String] = new AnotherFooImpl[String, String](thing) 
} 

現在:

def main(args: Array[String]): Unit = { 
    import Foo._ 

    val fooImpl = Foo[Int, String](new Thing) 
    val anotherFooImpl = Foo[String, String](new Thing) 

    println(fooImpl) 
    println(anotherFooImpl) 
} 

產量:

FooImpl([email protected]) 
AnotherFooImpl([email protected]) 
+0

很酷!你在使用類型參數:FooImpl [A1,B1] AnotherFooImpl [A2,B1]有什麼原因?他們可能是真的嗎?爲前:可能只是FooImpl [A,B] AnotherFooImpl [A,B] – Samar

+1

@Samar我已經修復了,謝謝你讓我通知。他們只是爲了測試和玩耍。它們通常是'A'和'B',它們不受任何類型的約束。 –