2013-04-14 42 views
4

我是新來的Guice,我想知道我能走多遠。 我有多個實現類GoogleUserInfoFacebookUserInfoTwitterUserInfo等使用的是工廠用Guice替代抽象工廠?

public class UserInfoFactory { 
    public UserInfo createFromJsonString(String jsonspec) { 
    . 
    . 
    . 

    } 
} 

創建由JSON字符串jsonspec它控制的UserInfo的實現類的是控制在這些類的接口UserInfo回。具體來說,有一個控制創建的JSON字符串元素domain。創建真的是使用GSON對jsonspec進行反序列化的功能。
我想知道是否有一種好方法可以用Guice依賴注入替換這個創建?

回答

6

您可以將Guice集成到工廠中,但是您的代碼可能與本例中的代碼完全相同。

這實際上是那些不能輕易替換的工廠之一,因爲它必須包含解析出jsonSpec的邏輯,並根據這個邏輯修改它返回的具體類型。比方說,工廠的稍微少簡化的版本是這樣的:

public class UserInfoFactory { 
    public UserInfo createFromJsonString(String jsonspec) { 
    if(getUserType(jsonSpec) == TWITTER) { 
     return new TwitterUserInfo(jsonSpec); 
    } else { /* ... */ } 
    } 

    private UserInfoType getUserType(String jsonSpec) { /* ... */ } 
} 

這邏輯有地方住,和你自己的UserInfoFactory似乎是一個完美的家。但是,因爲您使用的是new,所以您將無法注入任何TwitterUserInfo的依賴關係或其依賴關係的依賴關係,並且是Guice很好地解決的問題類型。

可以注入TwitterUserInfo作爲Provider,這將給你訪問到許多完全注入TwitterUserInfo的對象,只要你願意:

public class UserInfoFactory { 
    @Inject Provider<TwitterUserInfo> twitterUserInfoProvider; 

    public UserInfo createFromJsonString(String jsonspec) { 
    if(getUserType(jsonSpec) == TWITTER) { 
     TwitterUserInfo tui = twitterUserInfoProvider.get(); 
     tui.initFromJson(jsonSpec); 
     return tui; 
    } else { /* ... */ } 
    } 
} 

...,當然,這如果您只需要界面並且想要在將來某個時間更改具體的課程,則還允許您注入@Twitter Provider<UserInfo>。如果你想TwitterUserInfo接受構造函數的參數,Assisted injection幫助您創建一個TwitterUserInfoFactory,雖然,這將有助於它向immutability

public class UserInfoFactory { 
    @Inject TwitterUserInfo.Factory twitterUserInfoFactory; 

    public UserInfo createFromJsonString(String jsonspec) { 
    if(getUserType(jsonSpec) == TWITTER) { 
     return twitterUserInfoFactory.create(jsonSpec); 
    } else { /* ... */ } 
    } 
} 

// binder.install(new FactoryModuleBuilder().build(TwitterUserInfoFactory.class)); 
public class TwitterUserInfo implements UserInfo { 
    public interface Factory { 
    TwitterUserInfo create(String jsonSpec); 
    } 

    public TwitterUserInfo(@Assisted String jsonSpec, OtherDependency dep) { /* ... */ } 
} 

最後請注意:TwitterUserInfo可能沒有任何dependencies--這聽起來像是一個數據對象 - 所以讓你的班級完全如何發現它(與new)可能是最好的方法。儘管分離的接口和類可以減輕測試的負擔,但維護和理解成本很高。吉斯是一個非常強大的錘子,但並不是所有的東西都是釘子。

1

您可能想要使用輔助注射。

你需要用(@Assisted字符串jsonspec)(當然@Inject)

然後,你需要配置你的工廠類註釋中GoogleUserInfo,FacebookUserInfo和TwitterUserInfo你的構造

binder.install(new FactoryModuleBuilder().build(UserInfoFactory.class)); 

然後適當地綁定您要使用的任何Info提供程序。

I 認爲。我對自己很感興趣。

+0

輔助注入在這裏的研究是一件好事,但不夠聰明,以基於JSON類結果返回不同的具體類型。如此處所述,Guice將無法爲UserInfoFactory提供實現,因爲它無法實例化接口UserInfo,並且未調用FactoryModuleBuilder.implement接口就是FactoryModuleBuilder可能返回的所有接口。 –

+0

@JeffBowman - 如果你在Module.configure中有binder.install(新的FactoryModuleBuilder()。build(UserInfoFactory.class));在模塊public Class <?中添加一個函數擴展UserInfo> bindUserInfo(){返回GoogleUserInfo.class; }不起作用? (原諒我,我試圖從不同的角度來理解Guice,我有一個現有的應用程序,我使用的是Guice,我知道的是來自分析現有代碼庫。) –

+1

FactoryModuleBuilder通過檢查傳入'build'的接口(不是具體的類!),併爲其提供可注入的實現。當你調用實現的方法時,FactoryModuleBuilder接受方法的返回類型並實例化它,用方法參數和Injector中的所有其他參數填充'@ Assisted'參數。如果返回類型是_interface_,就像'UserInfo'一樣,你還需要調用'implement'來告訴它要創建哪個具體類型。這就是爲什麼它不能在這裏工作 - 具體類型在配置時固定。 –