用Guice取代抽象工厂?

pbh*_*ick 4 guice factory-pattern

我是Guice的新手,我想知道我能走多远.我有一个接口UserInfo与多个实现类GoogleUserInfo,FacebookUserInfo,TwitterUserInfo等正在使用工厂创建这些类

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

  }
}
Run Code Online (Sandbox Code Playgroud)

创建由JSON字符串控制,该字符串jsonspec控制UserInfo返回哪个实现类.具体来说,有一个JSON字符串元素domain来控制创建.创建实际上是jsonspec使用GSON 的反序列化的功能.
我想知道是否有一种很好的方法用Guice依赖注入替换这个创建?

Jef*_*ica 7

您可以将Guice集成到工厂中,但您的代码可能与此情况完全相同.

这实际上是那些无法轻易替换的工厂之一,因为它必须包含逻辑来解析jsonSpec并根据它来改变它返回的具体类型.让我们说工厂的略微简化的版本看起来像这样:

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

  private UserInfoType getUserType(String jsonSpec) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)

这个逻辑必须住在某个地方,你自己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 { /* ... */ }
  }
}
Run Code Online (Sandbox Code Playgroud)

......当然,@Twitter Provider<UserInfo>如果您只需要界面并希望在将来的某个时间改变具体类,那么它也允许您注入.如果你想TwitterUserInfo接受构造函数参数,辅助注入 将帮助你创建一个TwitterUserInfoFactory,这将有助于它的不变性:

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) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)

最后一点: TwitterUserInfo可能没有任何依赖关系 - 这对我来说听起来像是一个数据对象 - 所以让你的班级完全是你找到它的方式(带new)可能是最好的方法.虽然很容易将解耦的接口和类放在一起以便于测试,但维护和理解会有成本.Guice是一把非常强大的锤子,但并不是所有东西都是钉锤.