当前位置: 首页 > 知识库问答 >
问题:

使用guice注入游戏中某个特性/类的所有实现

穆招
2023-03-14

我有

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)
      }
    }
    
  • 共有1个答案

    吕英豪
    2023-03-14

    Guice只初始化它知道的类。所以你可以将所有的实现注入到你的外观中,并按你想要的顺序排列它们。每次添加新的实现时,你都需要改变这个外观...所以没那么好...

    备选方案

    要动态地告知guice您的实现,您需要进行一些反思。如果你能将你的Builder作为sealedtrait(获取你能在这里找到的所有子类的例子),你可以使用标准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。实例建筑商。同样在我的示例中,我假设您能够将类型参数TK移动到类型别名中(对于泛型,绑定和注入会有更多技巧——您可以自己尝试找到这种方法)。你的建筑商将是:

    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类中注入的类