您可以将 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
的依赖项,或其依赖项的依赖项 - 以及thatGuice 很好地解决了这一类问题。
You can inject TwitterUserInfo
as a 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
接受构造函数参数,辅助注射 https://code.google.com/p/google-guice/wiki/AssistedInject will帮助您创建一个TwitterUserInfoFactory
不过,这将有助于它不变性 http://www.javapractices.com/topic/TopicAction.do?Id=29:
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
可能没有任何依赖关系——对我来说这听起来像是一个数据对象——所以让你的类完全按照你找到它的方式(用new
)可能是最好的方法。虽然使用解耦的接口和类来简化测试固然很好,但维护和理解是有成本的。 Guice 是一把非常强大的锤子,但并不是所有的东西都是可以敲打的钉子。