Quelle est la motivation derrière l'annotation @ImplementedBy dans Guice?

10

J'ai récemment lu l' @ImplementedByannotation disponible dans Google Guice . Il permet au programmeur de spécifier une liaison entre une interface et son implémentation pour une utilisation future dans l'injection de dépendances. Il s'agit d'un exemple de liaison juste à temps .

Je suis assez habitué à définir des liaisons explicites dans mes modules, en utilisant la syntaxe suivante:

bind(SomeInterface.class).to(SomeInterfaceImplementation.class);

Selon la documentation, cela équivaut à l'utilisation suivante de l' @ImplementedByannotation:

@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}

Le seul gain que je peux voir ici est que le code est légèrement plus court. Dans le même temps, cette approche présente un inconvénient signalé à juste titre par les mêmes documents:

Utilisez @ImplementedByavec précaution; il ajoute une dépendance au moment de la compilation de l'interface à son implémentation.

Une telle dépendance peut ne pas être un problème dans de nombreux cas, mais je la vois personnellement comme une odeur de code.

Quels cas d'utilisation @ImplementedByvalent la peine d'être annotés?

Une façon possible semble être de l'utiliser dans le code d'une bibliothèque ou d'un framework. Comme décrit dans la documentation, l'annotation peut fournir une liaison par défaut facilement remplacée par une explicite.

Si un type se trouve à la fois dans une bind()instruction (comme premier argument) et possède l' @ImplementedByannotation, l' bind()instruction est utilisée. L'annotation suggère une implémentation par défaut qui peut être remplacée par une liaison.

De cette façon, en tant que développeur d'une bibliothèque, je peux fournir à mes utilisateurs une liaison prête à l'emploi qui peut être personnalisée quelque part dans le code client.

Est-ce la seule raison pour laquelle l'annotation existe? Ou y a-t-il quelque chose qui me manque? Puis-je gagner quelque chose en l'utilisant dans du code qui n'est qu'une application prenant en charge une logique métier et non une bibliothèque / un cadre à étendre?

toniedzwiedz
la source
2
Question connexe, peut-être en double (bien que votre titre soit plus clair): Guice's @ImplementedBy est-il mauvais?
Jeff Bowman
Pas un double strict, mais il y a eu quelques discussions intéressantes à ce sujet ici: stackoverflow.com/questions/6197178/…
Richard Vodden

Réponses:

8

Je pense que le danger ici est d'utiliser uniquement l' @ImplementedByannotation. Utilisé de manière appropriée, en conjonction avec les bind()instructions de votre module et ainsi de suite, c'est correct.

Avoir une implémentation par défaut est idéal pour les tests; vous ne voulez pas nécessairement avoir à définir explicitement une injection simulée à chaque fois que vous testez une classe qui a beaucoup de dépendances, ou si vous avez une classe dont beaucoup de choses dépendent (vous devez donc définir une maquette à chaque fois ).

Par exemple, vous pourriez avoir une classe:

@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}

Et puis NoOpDataServicec'est:

class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}

Vous n'utiliserez jamais cela dans votre code réel, évidemment; dans votre module Guice, vous liez une implémentation qui fait réellement quelque chose. Mais tous les tests sur les classes qui reçoivent une injection DataServicen'ont plus besoin d'avoir une liaison factice.

tl; dr Je suis d'accord avec vous que le fait que vos interfaces dépendent de votre implémentation peut être une odeur de code; mais il peut également supprimer le code passe-partout pour faciliter les tests. Ce n'est pas une fonctionnalité difficile à implémenter; et bien qu'il y ait un petit potentiel d'abus, en fin de compte, les conséquences ne peuvent pas être trop mauvaises (un service démarre par surprise), et il ne serait pas trop difficile à réparer même si cela se produit.

durron597
la source
3
Ajouter du code de test à la production?
Basilevs