我有以下情况:
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的注入类名为rock:
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(...),但在我的情况下它不是解决方案。
答案 0 :(得分:2)
听起来你要做的就是根据用户的注释绑定不同种类的音乐。这也称为the Robot Legs problem,但您可以将“Leg”替换为“User”,将“Foot”替换为“Music”。这可以在Guice中使用Private Modules,但您可能会发现更容易创建UserFactory。我会告诉你两种方式。
首先, Private Module方式。私有模块隐藏了来自外部世界的所有绑定,因此您可以暴露某些绑定而不会发生其他绑定。
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,否则您可以跳过该步骤。
另一种方式是跳过使用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()
来获取您的用户。当然,也许您的用户需要十几个其他注入的依赖项。在这种情况下,第一个选项看起来不错,或者您可以调查assisted injection。所有这些都是可行的选择,因此您需要考虑哪一种是适合您情况的灵活性和可读性的正确组合。
希望有所帮助!
答案 1 :(得分:0)
鉴于@Named不是一个选项我认为你也不能使用Binding Annotations。您可以向喷油器询问:
Injector injector = Guice.createInjector(new Module());
MusicInterface musicInterface = injector.getInstance(Key.get(String.class, Names.named("rock"))