简体   繁体   English

Scala工厂使用apply方法的泛型类型?

[英]Scala factory for generic types using the apply method?

Suppose that I have the following trait that defines an interface and takes a couple of type parameters... 假设我有以下特征来定义一个接口并采用几个类型参数......

trait Foo[A, B] {

    // implementation details not important

}

I want to use the companion object as a factory for concrete implementations of the trait. 我想使用伴侣对象作为特征的具体实现的工厂。 I also want to force users to use the Foo interface instead of sub-classing So I hide the concrete implementations in the companion object like so: 我还想强制用户使用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]

}

I want to be able to use the factory as follows: 我希望能够按如下方式使用工厂:

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

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

How do I implement the apply method to make this happen? 如何实现apply方法来实现这一目标? This SO post seems close to the mark. 这个SO帖子似乎接近标志。

How about: 怎么样:

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)
}

And now: 现在:

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)
}

Yields: 产量:

FooImpl(testing.X$Thing@4678c730)
AnotherFooImpl(testing.X$Thing@c038203)

Using TypeTags (to overcome erasure of type parameters), we can call the respective hidden implementations based on the type parameters passed in to the apply method like below. 使用TypeTags (为了克服类型参数的擦除),我们可以根据传递给apply方法的类型参数调用相应的隐藏实现,如下所示。 It correctly instantiates the respective implementations but the type information for Foo is lost, in fact its coming some garbage like _202 etc? 它正确地实例化了各自的实现,但是Foo的类型信息丢失了,实际上它会像_202那样出现一些垃圾? I don't know why that is happening and how to retain the correct types for Foo. 我不知道为什么会发生这种情况以及如何为Foo保留正确的类型。 Maybe someone can throw light on this. 也许有人可以对此有所了解。

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($sess.cmd123$Thing@50350b75)

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($sess.cmd123$Thing@51d80d6)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM