2016-09-25 5 views
2

は、私は形質の具体的な実装のためのファクトリとしてコンパニオンオブジェクトを使用したいapplyメソッドを使用するジェネリック型のスカラファクトリ?

trait Foo[A, B] { 

    // implementation details not important 

} 

...私はインターフェイスを定義し、型パラメータのカップルをとり、次の特性を持っていると仮定します。次のように

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] 

} 

私は工場を使用することができるようにしたい:私も、私はそうのようなコンパニオンオブジェクトでの具体的な実装を隠すので、サブクラス化するのではなく、Fooインタフェースを使用するようにユーザーを強制したい

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

(型パラメータの消去を克服するため)を使用すると、以下のように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]の理由で型パラメータを使用していますか?本当に正しいことがありますか? for:FooImpl [A、B]&AnotherFooImpl [A、B] – Samar

+1

@Samar私はそれを修正しました。彼らはテストと遊びのためのものでした。彼らは一般に「A」と「B」で、どんなタイプにも縛られていません。 –

関連する問題