Ci sono diversi modi in cui posso inizializzare oggetti complessi (con dipendenze iniettate e configurazione richiesta di membri iniettati), tutti sembrano ragionevoli, ma presentano vari vantaggi e svantaggi. Vi darò un esempio concreto:È una pratica buona o cattiva chiamare i metodi di istanza da un costruttore 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); }
}
Come si può vedere, il costruttore fa 3 cose, tra cui chiamare un metodo di istanza. Mi è stato detto che chiamare i metodi di istanza da un costruttore non è sicuro perché aggira i controlli del compilatore per i membri non inizializzati. Cioè Avrei potuto chiamare doSomething(0)
prima di impostare this.dependency
, che avrebbe compilato ma non funzionato. Qual è il modo migliore per refactoring questo?
Rendi statico lo
doSomething
e passare la dipendenza in modo esplicito? Nel mio caso reale ho tre metodi di istanza e tre campi membri che dipendono tutti l'uno dall'altro, quindi questo mi sembra un gran numero di hotplate in più per rendere tutti e tre questi statici.Spostare
addHandler
edoSomething
in un metodo@Inject public void init()
. Mentre l'uso con Guice sarà trasparente, richiede qualsiasi costruzione manuale per essere sicuro di chiamareinit()
oppure l'oggetto non sarà completamente funzionale se qualcuno dimenticherà. Inoltre, questo espone più dell'API, che sembrano entrambe idee sbagliate.Avvolgere una classe annidata per mantenere la dipendenza per assicurarsi che si comporta correttamente senza esporre ulteriore API:
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); }
Questo tira metodi di istanza su tutti i costruttori, ma genera un ulteriore livello di classi, e quando ho già avuto interiore e classi anonime (ad esempio il gestore) può diventare confuso - quando ho provato questo mi è stato detto di spostare ilDependencyManager
in un file separato, che è anche di cattivo gusto perché ora è più file per fare una singola cosa.
Quindi qual è il modo preferito per affrontare questo tipo di situazione?
@Steve: Ho appena rimosso i primi tag "pre" in modo che il codice mostri la sintassi con codice colore :) – SyntaxT3rr0r
Cool, non sapevo che funzionasse in quel modo. – Steve