2015-03-31 47 views
2

我正在使用Guice和FactoryModuleBuilder。通常,只需定義工廠的界面就足夠了,Guice將自動注入實施。Guice,FactoryModuleBuilder,多個實現和泛型

但是,我掙扎的部分是工廠中的方法使用泛型。假設我有以下幾點。由接口定義的構造實例的基本類型。

interface Foo<T> { 
    T get(); 
} 

並且Foo接口的兩個實現由以下兩個類定義。

class FooA<T> implements Foo<T> { 
    @Inject 
    FooA(@Assisted Class<T> clazz, @Assisted String s) {...} 
} 

class FooB<T> implements Foo<T> { 
    @Inject 
    FooB(@Assisted Class<T> clazz, @Assisted Integer i) {...} 
} 

然後我有下面定義的工廠接口,使用兩個自定義綁定註釋,允許我使用多個實現。

interface FooFactory { 
    @A Foo<T> build(Class<T> clazz, String s); 
    @B Foo<T> build(Class<T> clazz, Integer i); 
} 

我已經嘗試了一些可能的解決方案,但除了一個迄今爲止工作。有效的解決方案是基本編寫我自己的FooFactory的實現,如下所示。並且在模塊的configure方法中,將接口綁定到實現; bind(FooFactory.class).to(FooFactoryImpl.class);

class FooFactoryImpl { 
    Foo<T> build(Class<T> clazz, String s) { 
     return new FooA(clazz, s): 
    } 
    Foo<T> build(Class<T> clazz, Integer i) { 
     return new FooB(clazz, i); 
    } 
} 

但是,我有這個解決方案的一個問題。這些實例不是由Guice創建的,因此我失去了Guice附帶的空檢查。這與我沒有這個問題的其他工廠完全不同。這意味着我必須爲Foo的每個實現明確寫入空檢查。我想避免這種情況。

以下是我嘗試過的一些解決方案。

解決方案1:

FactoryModuleBuilder fmb = new FactoryModuleBuilder() 
    .implement(Foo.class, A.class, FooA.class) 
    .implement(Foo.class, B.class, FooB.class); 
install(fmb.build(FooFactory.class)); 

解決方案2:

FactoryModuleBuilder fmb = new FactoryModuleBuilder() 
    .implement(TypeLiteral.get(Foo.class), A.class, TypeLiteral.get(FooA.class)) 
    .implement(TypeLiteral.get(Foo.class), B.class, TypeLiteral.get(FooB.class)); 
install(fmb.build(TypeLiteral.get(FooFactory.class))); 

的示例代碼可在GitHub(如果有人有興趣)。

+0

您的FooA和FooB構造函數是否有任何注入的實例?他們應該嗎?我所看到的只有兩個@Assisted參數,這並不能解釋Guice在這裏的幫助。 – 2015-03-31 15:26:11

+0

當工廠方法本身是通用的時,我不認爲輔助注入是有效的。但如果你讓它成爲'FooFactory '它可以工作。 – 2015-03-31 18:59:14

+0

@JeffBowman,這是一個簡單的例子。儘管如此,無論構造函數是否有Guice自動注入的實例,您仍然希望Guice在自己的容器中管理這些新實例。另外,你得到免費的空檢查:) – ChristopherZ 2015-04-01 07:12:23

回答

1

據我所知,您不能設計AssistedInject工廠以這種方式工作。然而,在我看來,你在一堂課中做得太多了。因爲對Class<T>沒有任何限制,很明顯,在構造函數中沒有使用此類的任何方法,這意味着將行爲重構爲單獨的類應該相當容易。我知道這是樣板的一點點,這不是正是你想要的,但它可能是這個樣子:

interface FooDataFactory { 
    @A FooData build(String s); 
    @B FooData build(Integer i); 
} 

public class FooA<T> implements Foo<T> { 
    public FooA(FooData data) { 
     // You should know what class you need when you're actually calling the constructor. 
     // This way you don't even need to pass around Class<T> instances 
    } 
} 

如果這個方法不適合你的使用情況的工作,讓我知道,我我會編輯補償。

+0

FooData是接口還是具體類?它如何幫助Guice創建Foo的實例? – ChristopherZ 2015-04-10 19:58:24

+0

'FooData'是一個具體的類。 **你**實際上會使用'new'來創建Foo的實例。 – durron597 2015-04-10 19:59:31

+0

這似乎是提供FooFactory(例如,FooFactoryImpl)的實現的一個等效解決方案,這是我在問題中提到的。 – ChristopherZ 2015-04-11 03:57:43