あなたがやろうとしているのは、ユーザーの注釈に基づいてさまざまな種類の音楽をバインドすることです。これは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 を作成することです。( ImmutableMapはGuavaからのものです。)
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 は他にも数十個の注入された依存関係を必要とするかもしれません。その場合、最初のオプションが良さそうです。これらはすべて実行可能なオプションであるため、状況に応じて柔軟性と読みやすさの適切な組み合わせを検討する必要があります。
それが役立つことを願っています!