Existen varias maneras diferentes en que puedo inicializar objetos complejos (con dependencias inyectadas y la configuración requerida de miembros inyectados), todas parecen razonables, pero tienen varias ventajas y desventajas. Voy a dar un ejemplo concreto:¿Es una buena o mala práctica llamar a métodos de instancia desde un constructor 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); }
}
Como se puede ver, el constructor hace 3 cosas, incluyendo llamar a un método de instancia. Me han dicho que llamar a los métodos de instancia de un constructor no es seguro porque elude las comprobaciones del compilador para los miembros no inicializados. Es decir. Pude haber llamado al doSomething(0)
antes de configurar this.dependency
, que se hubiera compilado pero no funcionado. ¿Cuál es la mejor manera de refactorizar esto?
Hacer
doSomething
estática y pasar de la dependencia explícita? En mi caso real, tengo tres métodos de instancia y tres campos de miembros que dependen uno del otro, por lo que parece una repetición adicional para que los tres estén estáticos.Mueva
addHandler
ydoSomething
en un método@Inject public void init()
. Si bien el uso con Guice será transparente, se requiere una construcción manual para asegurarse de llamar alinit()
o de lo contrario el objeto no será completamente funcional si alguien se olvida. Además, esto expone más de la API, y ambas parecen malas ideas.Wrap una clase anidada para mantener la dependencia para asegurarse de que se comporta adecuadamente sin exponer API adicional:
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); }
Esto empuja los métodos de instancia fuera de todos los constructores, pero genera una capa extra de clases, y cuando ya tuve interior y las clases anónimas (por ejemplo, ese controlador) pueden volverse confusas: cuando probé esto, me dijeron que moviera el archivoDependencyManager
a otro archivo, lo que también es desagradable porque ahora hay varios archivos para hacer una sola cosa.
Entonces, ¿cuál es la forma preferida de tratar este tipo de situación?
@Steve: Acabo de eliminar las primeras etiquetas "pre" para que el código muestre el uso de la sintaxis codificada por colores :) – SyntaxT3rr0r
Genial, no sabía que funcionó de esa manera. – Steve