web-dev-qa-db-ja.com

複数の実装があるガイドとインターフェース

インターフェイスValidatorとこのインターフェイスの複数の実装がある場合。 Guiceで複数の実装のいずれかを注入するにはどうすればよいですか?これで、次のコードを使用して1つを挿入できることがわかりましたが、実装できるのは1つだけです。

public class MyModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(Validator.class).to(OneOfMyValidators.class);
  }
}

私がしたいのは:

Validator v1 = injector.getInstance(Validator1.class);
Validator v2 = injector.getInstance(Validator2.class);

それは可能ですか?

16
newbie

簡単な答え:注釈のバインド。これらは基本的に、完全な具象実装クラスへの依存を必要とせずに、依存者に特定のインスタンスまたは実装を指すヒントを与える方法です。

参照: https://github.com/google/guice/wiki/BindingAnnotations

たとえば、モジュールでは、次のようにします。

bind(Validator.class).annotatedWith(ValidatorOne.class).to(OneOfMyValidators.class);
bind(Validator.class).annotatedWith(ValidatorTwo.class).to(SomeOtherValidator.class);

そして、コンストラクターでは、次のことを行います。

@Inject
MyClass(@ValidatorOne Validator someValidator,
    @ValidatorTwo Validator otherValidator) {
  ...
}

注釈付きの値をInjectorから直接取得するには、次のようにGuice Keyクラスを使用する必要があります。

Validator v1 = injector.getInstance(Key.get(Validator.class, ValidatorOne.class));

ちなみに、バインディングアノテーションは、ランタイム定数を挿入するのに非常に便利です。次のbindConstantのコメントを参照してください。

https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/Binder.html

22
Andrew McNamee

Ejboyの提案と非常に似ていますが、異なるValidatorクラスを所有しているため、インスタンスを手動で作成するのではなく、クラス自体にバインドできます。

protected void configure() {
   ...
   Multibinder<Validator> mb = Multibinder.newSetBinder(binder(), Validator.class);
   mb.addBinding().to(Validator1.class);
   mb.addBinding().to(Validator2.class);
   mb.addBinding().to(Validator3.class);
   ...
}

次に、使用法の観点から見ます。コンストラクター注入による:

class UseCase {
    private Set<Validator> allOfThem;

    @Inject
    public UseCase(Set<Validator> allOfThem) {
        this.allOfThem = allOfThem;
        // e.g. iteratation
        for (Validator oneOfThem : allOfThem) {
            ...
        }
    }
}
8
Hartmut P.

JavaのServiceLoaderと同様に、複数の実装をインターフェースに動的にバインドするためのソリューションを探しているときに、このスレッドを見つけました。答えはより一般的なケースをカバーしていますが、セットから特定の実装を取得するために使用することもできます。 Multibinder 複数の実装をタイプにバインドできます:

public class ValidatorsModule extends AbstractModule {
  protected void configure() {
      Multibinder<Validator> multibinder
          = Multibinder.newSetBinder(binder(), Validator.class);
      multibinder.addBinding().toInstance(new ValidatorOne());
      multibinder.addBinding().toInstance(new ValidatorTwo());
  }
}

//Usage
@Inject Set<Validator> validators;
7
ejboy