3

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で入手できます(興味がある場合)。

4

1 に答える 1

1

私の知る限り、AssistedInject ファクトリをこのように動作するように設計することはできません。しかし、あなたは 1 つのクラスでやりすぎているように思えます。に制限がないため、コンストラクター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
    }
}

このアプローチがあなたのユースケースでうまくいかない場合は、私に知らせてください。修正するために編集します。

于 2015-04-09T21:00:47.893 に答える