2016-08-09 19 views
2

実行時に実装をスワップできるはずの私のアプリでDI用にGuiceを使用することを考えています。例では、要件説明するために以下に提供されています。クライアント名に基づいて実行時に機能を検証するためにバインドされるべき上記実施の実行時にGoogle Guiceを使用して依存関係を挿入する

class ValidationEngine { 
    public void validate(ValidationService vs) {} 
} 

class Client1_ValidationService implements ValidationService {} 
class Client2_ValidationService implements ValidationService {} 

一つを、クライアント1またはクライアント2

私はValidationEngineなどを変更することを考えたと言います上記のアプローチの問題は、@ Namedアノテーションへのパラメータが静的であることです。実際にはアノテーションはランタイム値を受け入れません。 Guiceにこの種の問題を解決するための他のアプローチはありますか?

答えて

0

あなたは、各ValidationService実装のために独自の注射器を作成するためにInjector.createChildInjectorを使用しようとすることができます

Injector client1Injector = injector.createChildInjector(new Module() { 
    @Override 
    public void configure(final Binder binder) { 
     binder 
      .bind(ValidationService.class) 
      .to(Client1_ValidationService.class); 
     } 
    }); 

ValidationEngine client1Engine = 
    client1Injector.getInstance(ValidationEngine.class) 

しかし、それはあなたが何らかの形ですべての子インジェクタを管理しなければならないことを意味します。

+0

これは問題のようです。物事を明らかにするために - もし私が5人のクライアントを持っていれば、私は5人のインジェクターで終わるでしょう。また、それらをHashMapに格納すると、クライアントIDを使用してインジェクタを取得するのに役立ちます。それは正しいアプローチですか? –

+0

@giri_colそうですね。 'ValidationService'実装ごとにインジェクタを保持する必要があります。それのようなもの - https://gist.github.com/KetothXupack/b4f6786a1590c7a2466be5f9523a564a – vsminkov

1

Guiceモジュールに構成情報を渡すことができます。

擬似コード:それはあなたがテストするための表面積を増大させて

main() { // your main method 
    flags = parseFlags() 
    injector = guice.createInjector(new MyModule(flags.validator)) 
} 

MyModule { // your guice module 
    constructor(validator): this.validator = validator; 
    configure() { 
     Class<ValidatorService> client_validator; 
     if this.validator == KNOWN_CLIENT1: 
      client_validator = Client1_ValidationService.class 
     else: 
      client_validator = Client2_ValidationService.class 
     bind(ValidationService.class).to(client_validator); 
    } 
} 

Guiceのは、これに対して警告しています。

@Inject 
private Injector injector; 

public ValidationService getValidationServiceForClient(String clientName) { 
    return injector.getInstance(Key.get(ValidationService.class, Names.named(clientName))); 
} 

2)もう一つの方法:https://github.com/google/guice/wiki/AvoidConditionalLogicInModules

0

1)のように、名前のインジェクタによって直接注入し

public class ValidationServiceProviderImpl implements ValidationServiceProvider { 

    @Inject 
    @Named("ClientA") 
    private ValidationService clientAValidationService; 

    @Inject 
    @Named("ClientB") 
    private ValidationService clientBValidationService; 

    public ValidationService getValidationServiceForClient(String clientName) { 
     switch (clientName) { 
      case "ClientA": return clientAValidationService; 
      case "ClientB": return clientBValidationService; 
     } 
     return null; // return default validationService for any other client 
    } 
} 

public interface ValidationServiceProvider { 
    ValidationService getValidationServiceForClient(String clientName); 
} 

構成:

Injector injector = Guice.createInjector(new AbstractModule() { 
    protected void configure() { 
     bind(ValidationService.class) 
      .annotatedWith(Names.named("ClientA")) 
      .to(ClientA_ValidationService.class); 
     bind(ValidationService.class) 
      .annotatedWith(Names.named("ClientB")) 
      .to(ClientB_ValidationService.class); 
     bind(ValidationServiceProvider.class) 
      .to(ValidationServiceProviderImpl.class); 
    } 
}); 

例使用プロバイダ:

直接

例使用した注射器は:

ValidationService clientA = 
    injector.getInstance(Key.get(ValidationService.class, Names.named("ClientA"))); 
ValidationService clientB = 
    injector.getInstance(Key.get(ValidationService.class, Names.named("ClientB"))); 
関連する問題