Guice と FactoryModuleBuilder を使用しています。通常、ファクトリーのインターフェースを定義するだけで十分で、Guice は自動的に実装を注入します。
ただし、私が苦労している部分は、ファクトリのメソッドがジェネリックを使用していることです。以下があるとします。インターフェイスによって定義された、構築されたインスタンスの基本型。
interface Foo<T> {
T get();
}
Foo
また、以下の 2 つのクラスで定義されているインターフェイスの 2 つの実装。
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) {...}
}
次に、複数の実装を使用できるようにする 2 つのカスタム バインディング アノテーションを使用して、以下に定義するファクトリ インターフェイスを作成します。
interface FooFactory {
@A Foo<T> build(Class<T> clazz, String s);
@B Foo<T> build(Class<T> clazz, Integer i);
}
私は多くの可能な解決策を試しましたが、これまでのところ1つを除くすべてが機能しています。うまくいった解決策は、基本的に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);
}
}
ただし、このソリューションには 1 つの問題があります。インスタンスは Guice によって作成されないため、Guice に付属する null チェックが失われます。これは、この問題を抱えていない他の工場とは大きく異なります。これは、 のすべての実装に対して明示的に null チェックを書かなければならないことを意味します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で入手できます(興味がある場合)。