1

次のような状況があります:

public class User {

@Inject
private MusicInterface movie;

}

public interface MusicInterface {
public void getTitle();
}

Guice構成クラスがあります:

public class Module extends AbstractModule {

    @Override
    protected void configure() {

        bind(MusicInterface.class).annotatedWith(Names.named("rock")).to(RockMusic.class);
        bind(MusicInterface.class).annotatedWith(Names.named("pop")).to(PopMusic.class);
        bind(User.class).annotatedWith(Names.named("user1").to(User.class);
        bind(User.class).annotatedWith(Names.named("user2").to(User.class);
    }
}

私の質問は次のとおりです: ユーザー クラスに私の欲しい音楽バインドを挿入する方法は?

例えば:

私のメインでは、ロックという名前の注入されたクラスで User1 を取得したい:

Injector injector = Guice.createInjector(new Module());

User user1 = injector.getInstance(Key.get(User.class,Names.named("user1")));

user1 に属性 RockMusic.class があり、後で user2 にポップ ミュージックを追加したいとします。

User user2 = injector.getInstance(Key.get(User.class,Names.named("user2")));

そして、このクラスには属性 PopMusic.class があります。

これどうやってするの?

User クラスで注釈 @Named(...) を使用できることはわかっていますが、私の場合は解決策ではありません。

4

2 に答える 2

2

あなたがやろうとしているのは、ユーザーの注釈に基づいてさまざまな種類の音楽をバインドすることです。これはRobot Legs problemとも呼ばれますが、"Leg" を "User" に、"Foot" を "Music" に置き換えることができます。これはGuice のプライベート モジュールを使用して可能ですが、代わりに UserFactory を作成する方が簡単な場合があります。両方の方法をお見せします。

まず、プライベートモジュールの方法です。プライベート モジュールはすべてのバインディングを外部から隠しているため、他のモジュールと競合することなく特定のモジュールを公開できます。

public class MyModule extends AbstractModule {
  @Override protected void configure() {
    install(privateModuleFor("user1", RockMusic.class));
    install(privateModuleFor("user2", PopMusic.class));
  }

  private static Module privateModuleFor(
      final String userName, final Class<? extends MusicInterface> musicClass) {
    return new PrivateModule() {
      @Override protected void configure() {
        // Bind the annotated user.
        bind(User.class).annotatedWith(Names.named(userName)).to(User.class);
        // Now bind the music class as if it's the only music class ever.
        bind(MusicInterface.class).to(musicClass);
        // The above two bindings are hidden, and available only in this module,
        // so Guice doesn't complain about two different competing
        // MusicInterfaces. In order to get access to the User binding
        // outside the module, expose it.
        expose(User.class).annotatedWith(Names.named(userName));
      }
    };
  }
}

@Named("user1") Userこれで、ロック ミュージックが好きなユーザーを取得するようリクエストできます。もちろん、メソッドで行ったように整理する必要はありません。必要に応じて MusicInterface のタイプを名前にバインドし、アノテーションのない MusicInterface をKey.get(MusicInterface.class, yourMusicTypeHere)PrivateModule にバインドすることもできますが、他の場所で名前付きの MusicInterfaces が必要な場合は、おそらくその手順をスキップできます。

もう 1 つの方法は、このバインドに Guice を使用しないことです。Guice は優れたソリューションですが、複雑なバインディングの状況では、設定する価値があるよりも面倒な場合があります。別の方法は、適切な種類の音楽を選択する軽量の UserFactory を作成することです。( ImmutableMapGuavaからのものです。)

public class UserFactory {
  private Map<String, Class<? extends MusicInterface>> musicMap =
      ImmutableMap.builder()
        .put("user1", RockMusic.class)    // You could also put instances here
        .put("user2", PopMusic.class)     // and skip using Guice entirely!
        .build();

  // Never inject Injector unless you don't know what you need until runtime,
  // which is exactly what is happening here.
  @Inject private Injector injector;
  @Inject private Provider<Dependency> someOtherUserDependency;

  public User createUser(String musicType) {
    Class<? extends MusicInterface> clazz = musicMap.get(musicType);
    return new User(injector.getInstance(clazz), someOtherUserDependency.get());
  }
}

UserFactoryこれで、ユーザーは注入して呼び出すことで利用できるようになりますuserFactory.create()。もちろん、あなたの User は他にも数十個の注入された依存関係を必要とするかもしれません。その場合、最初のオプションが良さそうです。これらはすべて実行可能なオプションであるため、状況に応じて柔軟性と読みやすさの適切な組み合わせを検討する必要があります。

それが役立つことを願っています!

于 2012-12-11T06:43:16.183 に答える
0

@Named がオプションではないことを考えると、Binding Annotations も使用できないと想定しています。インジェクターにそれを求めることができます:

Injector injector = Guice.createInjector(new Module());
MusicInterface musicInterface = injector.getInstance(Key.get(String.class, Names.named("rock"))
于 2012-12-10T19:46:09.320 に答える