2013-09-23 41 views
2

類型和註釋單身,我有幾個類實現interface Provider<Communication>和我使用的吉斯與@Named註釋根據需要約束他們,例如:檢索使用吉斯

@Singleton 
public class Verizon implements Provider<Call> { 
    ... 
} 

@Singleton 
public class TMobile implements Provider<Call> { 
    ... 
} 

bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
    Names.named("Verizon")).to(Verizon.class); 

bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
    Names.named("TMobile")).to(TMobile.class); 

是否有實施清潔方式一個工廠,是以名作爲參數,如:

public static <C extends Communication> Provider<C> getCallProvider(C communication) { 
    String providerName = communication.getProviderName(); 

    return [Guice's matching object for type Provider<?> and @Named = providerName]; 
} 

我用注射器嘗試,但吉斯不會採取通用的參數TypeLiteral:

public <C extends Communication> Provider<C> getCommunicationProvider(C communication) { 
    return injector.getInstance(Key.get(new TypeLiteral<CommunicationProvider<C>>() {}, 
    Names.named(communication.getProvider().getId()))); 
} 

此拋出:

com.google.inject.ConfigurationException: Guice configuration errors: 
    1) Provider<C> cannot be used as a key; It is not fully specified. 

回答

3

提供程序由吉斯管理;當您正確綁定FooProvider<Foo>時,您應該能夠請求FooProvider<Foo>,而無需任何其他工作。因此,你可能不希望這樣的:

bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
    Names.named("Verizon")).to(Verizon.class); 

相反,你可能希望這樣的:

bind(Call.class).annotatedWith(Names.named("Verizon")).toProvider(Verizon.class); 

...這將讓你注入@Named("Verizon") Provider<Call>@Named("Verizon") call。在這一點上你原來的要求是,因爲這很容易:

/** 
* Because of erasure, at compile time the injector can only guarantee that it 
* returns something that extends Communication, not necessarily C. The cast and 
* @SuppressWarnings will help with that. 
*/ 
@SuppressWarnings("unchecked") 
public static <C extends Communication> Provider<C> getCommunicationProvider(
    C communication) { 
    return (Provider<C>) injector.getProvider(Key.get(communication.getClass(), 
     Names.named(communication.toString()))); 
} 

還要注意的是,因爲擦除,有沒有其他的方式來獲得一個類文本類型的C所以使用的Call一個模擬或動態代理會失敗。

如果你想綁定SomeOtherInterface<Call>而不是Provider<Call>,你仍然可以這樣做,但你需要用Guice的Types util class動態創建ParameterizedType並用其作爲輸入​​。有關創建ParameterizedType實現的更多內容,請閱讀this SO answer

0

我認爲這是不可能的。您可以自己編寫一個工廠,並使用該界面更改代碼以使用工廠。或者你可以將你的接口綁定到一個提供者(但是這會導致更多的代碼)。

bind (new TypeLiteral<Provider<Call>>() {}).annotatedWith(
    Names.named("Verizon")).toProvider(new Provider<Provider<Call>>(){public Provider get(){return new Verizon();}}); 

(或者是你的供應商的吉斯 - 供應商?)

+0

該方法的問題在於工廠必須意識到所有可能的類型 - 另一方面,我試圖儘量保持通用。 – REAPP3R

+0

工廠應該知道,要創建什麼...如果沒有,請使用Reflections-API並使用命名模式來查找具體的實現。但我認爲這比工廠瞭解所有階級更醜陋。 –