Il y a plusieurs façons d'initialiser des objets complexes (avec des dépendances injectées et la configuration requise des membres injectés), tout cela semble raisonnable, mais présente divers avantages et inconvénients. Je vais vous donner un exemple concret:Est-ce une bonne ou une mauvaise pratique d'appeler des méthodes d'instance à partir d'un constructeur java?
final class MyClass {
private final Dependency dependency;
@Inject public MyClass(Dependency dependency) {
this.dependency = dependency;
dependency.addHandler(new Handler() {
@Override void handle(int foo) { MyClass.this.doSomething(foo); }
});
doSomething(0);
}
private void doSomething(int foo) { dependency.doSomethingElse(foo+1); }
}
Comme vous pouvez le voir, le constructeur fait 3 choses, y compris appeler une méthode d'instance. On m'a dit que l'appel de méthodes d'instance à partir d'un constructeur n'est pas sûr car cela évite les vérifications du compilateur pour les membres non initialisés. C'est à dire. J'aurais pu appeler doSomething(0)
avant de définir this.dependency
, ce qui aurait compilé mais pas travaillé. Quelle est la meilleure façon de refactoriser cela?
Faire
doSomething
statique et passer dans la dépendance explicitement? Dans mon cas, j'ai trois méthodes d'instance et trois champs de membre qui dépendent l'un de l'autre, donc cela semble être beaucoup plus pratique pour rendre ces trois éléments statiques. DéplacezaddHandler
etdoSomething
dans une méthode@Inject public void init()
.Bien que l'utilisation avec Guice soit transparente, il faut une construction manuelle pour être sûr d'appelerinit()
sinon l'objet ne sera pas entièrement fonctionnel si quelqu'un oublie. En outre, cela expose plus de l'API, qui semblent tous deux mauvaises idées.Wrap une classe imbriquée pour maintenir la dépendance pour vous assurer qu'il se comporte correctement sans exposer API supplémentaire:
class DependencyManager { private final Dependency dependency; public DependecyManager(Dependency dependency) { ... } public doSomething(int foo) { ... } } @Inject public MyClass(Dependency dependency) { DependencyManager manager = new DependencyManager(dependency); manager.doSomething(0); }
Cette tractions méthodes d'instance sur tous les constructeurs, mais génère une couche supplémentaire de classes, et quand j'avais déjà intérieur et les classes anonymes (par exemple ce gestionnaire) cela peut devenir déroutant - quand j'ai essayé ceci, on m'a dit de déplacer leDependencyManager
dans un fichier séparé, ce qui est également désagréable car il y a maintenant plusieurs fichiers pour faire une seule chose.
Alors, quelle est la meilleure façon de faire face à ce genre de situation?
@Steve: Je viens de supprimer les premières balises "pré" afin que le code montre en utilisant la syntaxe codée en couleur :) – SyntaxT3rr0r
Cool, ne savait pas que cela fonctionnait de cette façon. – Steve