假设我有以下特征来定义接口并采用几个类型参数......
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
如何实施public static void main(String[] args) {
// Your scanner code here.
int answer = processAndReturn(int1, int2);
System.out.println("Larger Integer: " + answer);
int lastDigit = processLargerInt(answer);
System.out.print("Last Digit: " + lastDigit);
}
public static int processAndReturn(int int1, int int2){
return Math.max(int1, int2);
}
public static int processLargerInt(int answer) {
return answer % 10;
}
方法来实现这一目标?这SO post似乎接近标记。
答案 0 :(得分:6)
怎么样:
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(testing.X$Thing@4678c730)
AnotherFooImpl(testing.X$Thing@c038203)
答案 1 :(得分: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($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)