我有
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点:
我怎么能注入特征“Builder”的所有实现? 我发现一堆问题朝着同一个方向发展(使用multibinder,TypeLiteral等,但没有一个问题涉及注入所有实现的问题。它只是关于“如何注入特定的实现”)我知道如何绑定多个实例使用multibinder;但不是如果它是一般类......
最后我想使用一种立面图案。有一个“构建器”要注入,它会获取所有实现注入并知道需要什么构建器(参见上面的match-case-fracment)。但是我没有使用匹配案例,而是关注了MapBinder。类似于将Builder实现绑定到Map的东西,它将类用作键。
e.g。 (伪码)
class BuildingComponent @Inject()(builder: Map[Class,Builder]){
def doIt(item: Any) = {
builder.get(item.class).build(item)
}
}
答案 0 :(得分:1)
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,例如:如果是play框架,你需要输入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]
。
更新(添加了如何处理类型化实施的示例)
例如:您需要额外的类来保存您的砖类型信息。我abstract class
使用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)
就是好的
int arrsize;
BYTE copyrow[18];
arrsize = sizeof(copyrow);