我正在使用Guice和FactoryModuleBuilder。通常,仅定义工厂的接口就足够了,Guice将自动注入实现。
然而,我正在努力的部分是工厂中的方法使用泛型。假设我有以下内容。由接口定义的基本类型的构造实例。
interface Foo<T> {
T get();
}
以下两个类定义的Foo
接口的两个实现。
class FooA<T> implements Foo<T> {
@Inject
FooA(@Assisted Class<T> clazz, @Assisted String s) {...}
}
class FooB<T> implements Foo<T> {
@Inject
FooB(@Assisted Class<T> clazz, @Assisted Integer i) {...}
}
然后我有如下定义的工厂界面,使用两个自定义绑定注释,允许我使用多个实现。
interface FooFactory {
@A Foo<T> build(Class<T> clazz, String s);
@B Foo<T> build(Class<T> clazz, Integer i);
}
我已经尝试了许多可能的解决方案,但迄今为止只有一个解决方案。有效的解决方案是基本编写我自己的FooFactory
实现,如下所示。在模块的configure
方法中,将接口绑定到实现; bind(FooFactory.class).to(FooFactoryImpl.class);
class FooFactoryImpl {
Foo<T> build(Class<T> clazz, String s) {
return new FooA(clazz, s):
}
Foo<T> build(Class<T> clazz, Integer i) {
return new FooB(clazz, i);
}
}
但是,我对此解决方案存在一个问题。实例不是由Guice创建的,因此我丢失了Guice附带的空检查。这与我没有这个问题的其他工厂截然不同。这意味着我必须为Foo
的每个实现显式写入空检查。我想避免这种情况。
以下是我尝试的一些解决方案。
解决方案1:
FactoryModuleBuilder fmb = new FactoryModuleBuilder()
.implement(Foo.class, A.class, FooA.class)
.implement(Foo.class, B.class, FooB.class);
install(fmb.build(FooFactory.class));
解决方案2:
FactoryModuleBuilder fmb = new FactoryModuleBuilder()
.implement(TypeLiteral.get(Foo.class), A.class, TypeLiteral.get(FooA.class))
.implement(TypeLiteral.get(Foo.class), B.class, TypeLiteral.get(FooB.class));
install(fmb.build(TypeLiteral.get(FooFactory.class)));
示例代码位于GitHub(如果有人有兴趣)。
答案 0 :(得分:1)
据我所知,您不能设计AssistedInject工厂以这种方式工作。但是,在我看来,你在一堂课中做得太多了。由于您对Class<T>
没有限制,很明显您在构造函数中没有使用此类的任何方法,这意味着它应该相当容易将行为重构为一个单独的类。我知道这是一个模板,它不是你想要的,但它可能看起来像这样:
interface FooDataFactory {
@A FooData build(String s);
@B FooData build(Integer i);
}
public class FooA<T> implements Foo<T> {
public FooA(FooData data) {
// You should know what class you need when you're actually calling the constructor.
// This way you don't even need to pass around Class<T> instances
}
}
如果这种方法对您的用例不起作用,请告诉我,我会进行编辑以进行补偿。