Vous pouvez intégrer Guice en usine, mais votre code est probablement mieux comme il est dans ce cas.
C'est en fait l'une de ces usines qui ne peuvent pas être remplacées facilement, car elle doit contenir la logique pour analyser le jsonSpec
et changer le type concret qu'il renvoie en fonction de cela. Disons que la version légèrement moins simplifiée de l'usine ressemble à ceci:
public class UserInfoFactory {
public UserInfo createFromJsonString(String jsonspec) {
if(getUserType(jsonSpec) == TWITTER) {
return new TwitterUserInfo(jsonSpec);
} else { /* ... */ }
}
private UserInfoType getUserType(String jsonSpec) { /* ... */ }
}
Cette logique doit vivre quelque part, et votre propre UserInfoFactory
semble comme une maison parfaite. Toutefois, étant donné que vous utilisez new
, vous ne pourrez pas injecter l'une des dépendances de TwitterUserInfo
, ou les dépendances de ses dépendances - et que est le type de problème que Guice résout joliment.
Vous peut injecter TwitterUserInfo
comme Provider
, qui vous donnera accès au plus grand nombre TwitterUserInfo
entièrement injecté des objets que vous souhaitez:
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 { /* ... */ }
}
}
... et, bien sûr, que vous permet également d'injecter un @Twitter Provider<UserInfo>
si vous avez seulement besoin de l'interface et que vous voulez faire varier la classe concrète dans le futur.Si vous voulez TwitterUserInfo
accepter les paramètres du constructeur, Assisted injectionvous allez aider à créer un TwitterUserInfoFactory
bien, qui l'aidera vers 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) { /* ... */ }
}
Une note finale:TwitterUserInfo
ne probablement pas une dependencies-- cela ressemble à un objet de données pour moi - donc laisser votre classe exactement comment vous l'avez trouvé (avec new
) est probablement la meilleure approche. Bien qu'il soit agréable d'avoir des interfaces et des classes découplées pour faciliter les tests, la maintenance et la compréhension ont un coût. Guice est un marteau très puissant, mais tout n'est pas vraiment un clou à marteler.
L'injection assistée est une bonne chose à rechercher ici mais n'est pas assez intelligente pour renvoyer différents types de béton basés sur le résultat de la classe JSON. Comme spécifié ici, Guice ne parviendra pas à fournir une implémentation pour UserInfoFactory, car il ne peut pas instancier l'interface UserInfo, et sans appeler 'FactoryModuleBuilder.implement', l'interface est tout ce que FactoryModuleBuilder peut renvoyer. –
@JeffBowman - donc si vous avez dans Module.configure binder.install (new FactoryModuleBuilder(). Build (UserInfoFactory.class)); ajouter une fonction au module public Class extends UserInfo> bindUserInfo() {return GoogleUserInfo.class; } ne fonctionnerait pas? (Pardonnez-moi, j'essaie de comprendre Guice d'un point de vue différent de la normale.) J'ai une application existante avec laquelle je travaille qui utilise Guice et ce que je sais provient d'une tentative d'analyse de la base de code existante. .) –
FactoryModuleBuilder fonctionne en inspectant l'interface (pas la classe concrète!) Passée dans 'build' et en fournissant une implémentation injectable pour cela. Lorsque vous appelez la méthode de cette implémentation, FactoryModuleBuilder prend le type de retour de la méthode et l'instancie, en remplissant les paramètres '@ Assisted' avec les arguments de méthode et tout le reste de l'injecteur. Si le type de retour est un _interface_, comme 'UserInfo', vous devez également appeler' implement' pour indiquer le type concret à créer. C'est pourquoi cela ne fonctionnera pas ici - le type concret est fixé au moment de la configuration. –