【问题标题】:Guice, FactoryModuleBuilder, multiple implementations, and genericsGuice、FactoryModuleBuilder、多种实现和泛型
【发布时间】:2015-03-31 12:02:27
【问题描述】:

我正在使用 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 获得(如果有人感兴趣的话)。

【问题讨论】:

  • 你的 FooA 和 FooB 构造函数有注入实例吗?他们应该吗?我看到的只是两个@Assisted 参数,这并不能解释 Guice 在这里有什么帮助。
  • 当工厂方法本身是通用的时,我认为辅助注入不起作用。但是,如果您将其设为FooFactory&lt;T&gt;,它就可以工作。
  • @JeffBowman,这是一个简化的例子。尽管如此,无论构造函数是否有任何 Guice 自动注入的实例,您仍然希望 Guice 在其自己的容器中管理这些新实例。另外,您可以获得免费的空值检查 :)
  • @TavianBarnes,这意味着我必须获得的工厂数量会很大。例如,FooFactory&lt;String&gt; f1FooFactory&lt;Integer&gt; f2FooFactory&lt;Double&gt; f3 等。

标签: java guice assisted-inject


【解决方案1】:

据我所知,您无法将 AssistedInject 工厂设计为以这种方式工作。但是,在我看来,您在一堂课上做得太多了。因为您对Class&lt;T&gt; 没有任何限制,所以很明显您没有在构造函数中使用该类的任何方法,这意味着将行为重构为一个单独的类应该相当容易。我知道这有点像样板文件,并不是你想要的,但它可能看起来像这样:

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
    }
}

如果此方法不适用于您的用例,请告诉我,我会进行修改以进行补偿。

【讨论】:

  • FooData 是接口还是具体类?它如何帮助 Guice 创建 Foo 的实例?
  • FooData 是一个具体的类。 实际上会使用 new 创建 Foo 的实例。
  • 这似乎是提供我在问题中的 FooFactory(例如 FooFactoryImpl)实现的等效解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 2012-12-10
  • 2020-04-02
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多