Guice 只初始化它知道的类。因此,您可以将所有实现注入到您的外观中并根据需要对其进行排序。每次添加新实现时,您都需要更改此外观。所以不太好..
替代方案
要动态地通知 guice 您的实现,您需要进行一些反思。如果您可以将Builder 作为sealed 特征(获取所有子类的示例,您可以找到here)或使用第三方库(例如reflections),则可以使用标准scala。
我会解释最后一个案例
您需要在 build.sbt 中导入:
libraryDependencies ++= Seq(
"com.google.inject.extensions" % "guice-multibindings" % "<your guice version>",
"org.reflections" % "reflections" % "0.9.11")
您需要创建模块并通知 guice,例如如果是播放框架,您需要放入 application.conf
play.modules.enabled += "com.example.MyModule"
现在,我假设您能够将所有实现放入同一个包中(您可以查看文档如何在其他情况下获取所有实现)。假设它是com.example.builders。同样在我的示例中,我假设您能够将类型参数 T 和 K 移动到类型别名中(使用泛型,绑定和注入将有更多技巧 - 您可以尝试自己找到这种方式)。你的建造者将是:
trait Builder {
type T
type K
def build(brick: T) : K
}
现在到你的模块MyModule:
package com.example
import com.google.inject.AbstractModule
import com.google.inject.multibindings.Multibinder
import org.reflections.Reflections
class MyModule extends AbstractModule {
override def configure(): Unit = {
import scala.collection.JavaConverters._
val r = new Reflections("com.example.builders")
val subtypes = r.getSubTypesOf(classOf[Builder])
val executorBinder = Multibinder.newSetBinder(binder(), classOf[Builder])
subtypes.asScala.foreach {clazz =>
executorBinder.addBinding().to(clazz)
}
}
}
最后,你可以在需要的地方注入builders: java.util.Set[Builder]。
更新(添加了如何处理类型化实现的示例)
例如:你需要额外的类来保存你的砖类型信息。只要Builder 是特征,我就使用abstract class 应该没问题
import scala.reflect.runtime.universe._
trait Builder[T, K] {
def build(brick: T): K
}
abstract class TypeChecker[T: TypeTag] {
this: Builder[T, _] =>
def isDefinedAt[C: TypeTag](t: C) = {
typeOf[C] =:= typeOf[T]
}
}
class Foo
class Baa
class House
// first builder implementation
class StringBuilder
extends TypeChecker[Foo]
with Builder[Foo, String] {
override def build(brick: Foo) = {
println("StringBuilder")
""
}
}
// second builder implementation
class HouseBuilder
extends TypeChecker[Baa]
with Builder[Baa, House] {
override def build(brick: Baa) = {
println("HouseBuilder")
new House
}
}
// our set of builders
val s: Set[Builder[_, _] with TypeChecker[_]] = Set(
new StringBuilder,
new HouseBuilder
)
// here we check and apply arrived brick on our set of builders
def check[T: TypeTag](t: T) =
s.filter(_.isDefinedAt(t)).
foreach {b => b.asInstanceOf[Builder[T, _]].build(t)}
check(new Foo)
check(new Baa)