简体   繁体   English

Scala工厂方法与泛型

[英]Scala factory method with generics

I have a couple of objects for which I'm trying to write a factory method. 我有几个对象,我正在尝试编写工厂方法。

Simplified, these are: 简化,这些是:

case class a[a1,a2](j:a1, k:a2) {}
case class b[b1,b2](j:b1, k:b2) {}

I would like to create a method which would allow me to pass in the type, and get an instance of that class. 我想创建一个方法,允许我传入类型,并获得该类的实例。 I am trying to get to something like this: 我想尝试这样的事情:

class myfactory[T] {
   def make[K,L](p1: K, p2: L): T[K,L] = {
     new T(p1,p2)
   }
}

That obviously doesn't work (for various reasons, including 'T cannot take parameters'), but is there an elegant solution for creating something like this? 这显然不起作用(由于各种原因,包括'T不能参数'),但有没有一个优雅的解决方案来创建这样的东西?

0__'s answer is almost there. 0 __的回答几乎就在那里。 If you make the Factory[A[_,_]] a typeclass you are all set. 如果你使Factory[A[_,_]]成为一个类型类,那么你就完成了。 Here is an example with the names standardised: 以下是标准化名称的示例:

// enable higher kinded types to prevent warnings
import scala.language.higherKinds

// our case classes
case class A[A1,A2](j:A1, k:A2)
case class B[B1,B2](j:B1, k:B2)

// Define our factory interface
trait Factory[T[_,_]] {
  def make[P1,P2](p1: P1, p2: P2): T[P1,P2]
}

// Companion class makes factory easier to use
object Factory {
  def apply[T[_, _]](implicit ev: Factory[T]) = ev
}

// Add implicit implementations of Factory[A]
implicit object AFactory extends Factory[A] {
  def make[P1,P2](p1: P1, p2: P2): A[P1,P2] = A(p1, p2)
}

// Add implicit implementations of Factory[B]
implicit object BFactory extends Factory[B] {
  def make[P1,P2](p1: P1, p2: P2): B[P1,P2] = B(p1, p2)
}

Now test test the factory in the REPL 现在在REPL中测试工厂的测试

scala> val a = Factory[A].make("one", 2)
a: A[String,Int] = A(one,2)

scala> val b = Factory[B].make(1, "two")
b: B[Int,String] = B(1,two)

The new keyword cannot be used with a type parameter, only a concrete class, because the instantiation is checked at compile time. new关键字不能与类型参数一起使用,只能与具体类一起使用,因为在编译时会检查实例化。 You can work around this using reflection . 你可以使用反射来解决这个问题。

The probably better approach is to provide specific factories. 可能更好的方法是提供特定的工厂。

Eg 例如

trait Factory[A[_,_]] {
  def make[P, Q](p: P, q: Q): A[P, Q]
}

case class a[a1,a2](j:a1, k:a2) {}

object AFactory extends Factory[a] {
  def make[P, Q](p: P, q: Q): a[P, Q] = a(p, q)
}

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

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