我有
trait Builder[T, K] {
def build(brick: T) : K
对于这个特性,我有多个实现。。。
class StringBuilder extends Builder[Foo, String] { ... }
class HouseBuilder extends Builder[Baa, House] { ... }
class BaaBuilder extends Builder[Baz, Int] { ... }
根据给定的类型,我想从一个实现中选择。类似这样的东西(伪代码):
class BuildingComponent @Inject()(builder: Set[Builder]){
def doIt(item: Any) = {
item match {
case _: Foo => builder.filter(Foo).build(item)
case _: Baa => builder.filter(Baa).build(item)
case _: Baz => builder.filter(Baz).build(item)
}
}
所以2点:
>
如何注入trait“Builder”的所有实现??我发现了很多问题都是朝着同一个方向发展的(使用multibinder、TypeLiteral等,但没有一个问题涉及注入所有实现。这只是关于“如何注入特定的实现”),我知道如何使用multibinder绑定多个实例;但如果它是一个泛型类,就不是了。。。
最后,我想使用一种门面模式。有一个“构建器”要注入,它可以注入所有的实现,并且知道需要什么构建器(参见上面的匹配案例分形)。但是我没有使用匹配案例,而是关注了MapBinder。类似于将Builder实现绑定到Map,它使用类作为键。
例如(伪代码)
class BuildingComponent @Inject()(builder: Map[Class,Builder]){
def doIt(item: Any) = {
builder.get(item.class).build(item)
}
}
Guice只初始化它知道的类。所以你可以将所有的实现注入到你的外观中,并按你想要的顺序排列它们。每次添加新的实现时,你都需要改变这个外观...所以没那么好...
备选方案
要动态地告知guice您的实现,您需要进行一些反思。如果你能将你的Builder
作为sealed
trait(获取你能在这里找到的所有子类的例子),你可以使用标准scala,或者使用第三方库(例如反射)。
我会解释最后一个案例
您将需要导入您的build.sbt:
libraryDependencies ++= Seq(
"com.google.inject.extensions" % "guice-multibindings" % "<your guice version>",
"org.reflections" % "reflections" % "0.9.11")
您需要创建模块并通知guice,例如,在play framework的情况下,您需要将其放入应用程序中。形态
play.modules.enabled += "com.example.MyModule"
现在,我假设您能够将所有实现放在同一个包中(您可以查看文档,了解如何在其他情况下获取所有实现)。假设它是com。实例建筑商
。同样在我的示例中,我假设您能够将类型参数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。在需要的地方设置[Builder]
。
更新(添加了如何处理类型化实现的示例)
例如:您将需要额外的类来保留您的砖类型信息。我使用了抽象类,只要生成器是特性,它就可以了
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)
在Play 2.2中,我创建了GlobalActor制作类 我想将游戏框架升级到 2.5。Play.current在play 2.5中被弃用,所以我使用注入器修改了这个类,但注入器始终为Null。我需要如何使这门课在 Play 2.5 中工作?
我们是这样做的: 但是我们有很多类具有as依赖性,我们不想每次创建实例时都添加这些代码。 那么,有没有办法在创建B的实例时自动注入A的实例?
我用玩Web应用程序(没什么不寻常的)。Guice用于依赖注入。如何在类构造函数中注入属性值?代码如下。 在当前配置中,如果不运行应用程序,就无法测试。我希望能够在单元测试中实例化。完美的解决方案[从我的角度来看]应该是这样的: 不幸的是,这段代码不起作用,因为Guice没有“my”。bar绑定: 没有绑定使用 @com.google.inject.name.Named(value=my.bar)
我正在努力实现DI,特别是使用guice的构造函数注入。我很难理解如何将泛型的类类型注入到构造函数中。 我的课程如下: 我可以在运行时使用guice将类的类型注入构造函数吗?简而言之,我可以使用guice注入Foo构造函数吗?
我有一个已有的名为Legacy的类,它大部分是用旧学校的单例模式编写的。现在我想介绍一个新的领域,我想使用Guice。Legacy本身不受Guice控制,它由另一个服务类使用(在服务类内部,它调用Legacy类的getInstance()来检索Legacy对象),并且该服务类是使用Guice注入器创建的。 我尝试的是将方法注入到Legacy类中 并且在服务的模块文件中,我绑定了NewField对象
我是Guice注入的新手。如何将类注入到将在静态方法中使用的静态变量中? 这是我想在 doLocalize() 方法中使用注入的变量 b 的类。 这是我想要对其执行guice注入的模块类。 注意:我不能改变我的模块和B类,因为它来自另一个依赖项。 我想在我的A类中注入的类