2012-12-10 65 views
1

我有以下情況:如何配置Guice,它注入類我想要的綁定?

public class User { 

@Inject 
private MusicInterface movie; 

} 

public interface MusicInterface { 
public void getTitle(); 
} 

,並有吉斯配置類:

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); 
    } 
} 

我的問題是: 如何注入到用戶級通緝我的音樂綁定?

例如:

在我的主

我想叫巖注射類來獲得用戶1:

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。

我該怎麼做?

我知道我可以在用戶類中使用標註@Named(...),但它不是我的情況的解決方案。

+0

什麼表達你的「想要的」綁定是什麼?爲什麼一個用戶會得到搖滾音樂和另一個流行音樂? –

回答

2

這聽起來像你試圖做的是綁定基於用戶的註釋不同品種的音樂。這也被稱爲the Robot Legs problem,除了可以使用「用戶」和「腳」與「樂」取代「腿」。這是可能的吉斯使用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是一個很好的解決方案,但對於一些複雜的綁定情況來說,它可能比設置值得的麻煩更麻煩。您的替代方案是創建一個輕量級的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並調用。當然,也許你的用戶需要一打其他的注入依賴。在這種情況下,第一個選項看起來不錯,或者您可以調查assisted injection。所有這些都是可行的選項,因此您需要考慮哪種方案適合您的情況,是靈活性和可讀性的正確組合。

希望有幫助!

+0

那我真的很想,謝謝你!:) – Eiv

+0

@Ev很高興幫助!一旦您滿意,請記住將您的個人最有用的答案標記爲已接受(帶有複選標記)。 –

0

鑑於@Named是不是一種選擇,我sssuming你也不能使用綁定註釋。你可以問它的注射器:

Injector injector = Guice.createInjector(new Module()); 
MusicInterface musicInterface = injector.getInstance(Key.get(String.class, Names.named("rock")) 
+0

你誤會了我:(我編輯我的帖子的例子 – Eiv

+0

我仍然困惑,因爲我不知道你是如何做到這一點的: User user1 = injector.getInstance(Key.get(User.class, Names.named(「user1」))); User user2 = injector.getInstance(Key.get(User.class,Names.named(「user2」))); 您將如何命名同一個類兩次?你認爲使用泛型而不是?像用戶 user = injector.getInstance(Key.get(new TypeLiteral >(){})) –