|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
[JAVA] costruttori e metodi set incrociati
Oggi sono incappato in questo problema:
Ho due classi A e B che inizialmente avevano i costruttori che prendevano come parametro il tipo dell'altra Codice:
public A(B istanza) { }
public B(A istanza) { }
Allora ho pensato di sostituire i costruttori con dei metodi set. Codice:
public class B { public void set(A istanza) { } }
public class A { public void set(B istanza) { } }
ammettiamo che le due classi abbiano un altro metodo "execute" che al suo interno utilizza l'istanza dell'altra classe Codice:
public class B {
private A istanza;
public void set(A istanza) { this.istanza = istanza; }
public void execute() { istanza.test(); }
}
Codice:
public void execute() {
if (istanza != null) istanza.test();
}
Ultima modifica di blackskop : 08-01-2011 alle 18:31. |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
Una possibile soluzione di cui mi vergogno molto è lasciare i costruttori originari e inizializzare il tutto così:
Codice:
A a = null;
B b = new B(a);
a = new A(b);
b = new B(a);
|
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: May 2005
Città: Roma
Messaggi: 7938
|
scusa ma la domanda mi sorge spontanea....devi per forza avere questi "riferimetni" incrociati???
per risolvere il problema dei set chiamali semplicemente setA, setB, setC....
__________________
My gaming placement |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
|
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: May 2005
Città: Roma
Messaggi: 7938
|
sai benissimo che i nomi li definisci tu, io di solito uso questo "standard"
nomeMetodo per i setters and getters setNomeVariabile(Object nomeVariabile){...} Object getNomeVariabile(){...} quindi, nel caso di costruttore, basterebbe mettere setNomeClasse. sono tutte cose ovvie, ma magari (mi ci sono trovato molte volte io) sono talmetne banali da sfuggirti...
__________________
My gaming placement |
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
Quote:
|
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
secondo me ci deve essere un errore di progettazione, due classi distinte che non esistono l'una senza l'altra non hanno molto senso
|
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
puoi descrivere più o meno cosa devi fare?
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
Nel mio caso specifico ho un JPanel che contiene svariati componenti e che si occupa soltanto di aggiornare questi componenti con delle informazioni che gli vengono passate da svariate classi che gestiscono la logica. Quindi dal JPanel vengono invocati i metodi nelle classi che gestiscono la logica che a loro volta invocano altri metodi nel JPanel.
Codice:
public class JPanel {
private Manager1 manager1;
private Manager2 manager2;
private Manager3 manager3;
...
public void execute1() {
manager1.test();
manager2.test();
}
public void execute2() {
manager2.test();
manager3.test();
}
public void execute3() {
manager1.test();
manager3.test();
}
public void setManager1(Manager1 manager1) { this.manager1 = manager1; }
public void setManager2(Manager2 manager2) { this.manager2 = manager2; }
public void setManager3(Manager3 manager3) { this.manager3 = manager3; }
public void test1(String txt) {
;
}
public void test2(String txt) {
;
}
public void test3(String txt) {
;
}
}
class Manager1 {
private JPanel panel1;
public void execute() { panel1.test1("pippo"); }
public void setPanel1(JPanel panel1) { this.panel1 = panel1; }
public void test() { ; }
}
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2780
|
Una delle due classi potrebbe "prevalere" sull'altra allocando essa stessa l'istanza dell'altra:
Codice:
public A() {
this.b=new B(this);
}
public B(A istanza) { }
|
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
non so se è una buona cosa passare il riferimento a un oggetto "in costruzione" (cioè, mi sembra di ricordare che non lo sia, mi sbaglio?)
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Altrimenti nessun problema.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Il this passato nel costruttore è un po' complicato perchè fila liscio, con o senza thread, a patto che, dove il "che" è seguito da un po' di fatti che riguardano l'accessibilità, diretta o indiretta, dei campi, sia nella classe che pubblica il this, sia nelle sue sottoclassi.
La questione è in verità molto semplice: quando pubblichiamo il this, chi lo riceve può accedere ai membri del tipo di quel this. Se i membri accessibili dipendono, direttamente o indirettamente, dal valore di un campo che nel costruttore "pubblicante" è inizializzato dopo la pubblicazione o il cui accesso è sovrascritto dal tipo runtime di quel this allora salterà fuori una null pointer exception, se siamo fortunati e il campo in questione è un riferimento, se è un primitivo siamo anche più nei guai. esempio: Codice:
public class Prova {
public static void main(String[] args) {
A a = new A();
}
}
class A {
private String x;
A() {
B b = new B(this);
x = "hello";
}
String getX() {
return x.toString();
}
}
class B {
B(A a) {
String y = a.getX();
}
}
Codice:
public class Prova {
public static void main(String[] args) {
A a = new C();
}
}
class A {
private String x;
A() {
x = "hello";
B b = new B(this);
}
String getX() {
return x.toString();
}
}
class B {
B(A a) {
String y = a.getX();
}
}
class C extends A {
private String y;
C() {
y = "world";
}
@Override
String getX() {
return y.toString();
}
}
I due setter sono la soluzione più efficace. Non sono la migliore perchè giustamente si dice "così però non riesco ad obbligare il programmatore a invocare quel setter prima di usare i metodi". Giustissimo, preferibile ed encomiabile ma devi cambiare il design. Nota che quando due oggetti vogliono comunicare l'uno con l'altro essi lo fanno condividendo una parte di sè stessi, non tutto quanto, altrimenti cessano di essere due oggetti e al più sono un oggetto solo definito in due unità di compilazione diverse. Ci sono tante soluzioni ma nessuna di quelle che mi vengono in mente sono così poco "invasive" come i setter. |
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Aug 2008
Messaggi: 308
|
Quote:
Volendo cambiare il design cosa suggerisci? Non mi vorrei buttare in IoC e DI a colpi di spring
|
|
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Tutto dipende dall'interpretazione che vuoi dare al problema. Ad esempio potremmo immaginare che la necessità dell'esistenza in A di un riferimento a B per l'esecuzione di talune operazioni sia rappresentata dall'esistenza di una parte di A indefinita fino all'arrivo di un B.
Puoi rappresentare questa parte indefinita con una classe interna. Supponiamo ad esempio che A sia: Codice:
class A {
private B b;
public void setB(B b) { this.b = b; }
public void operazione1SuB() { System.out.println(b.toString()); }
public void operazione2SuB() { System.out.println(b.hashCode()); }
public void operazioneNSuB() { System.out.println(b.getClass()); }
}
Codice:
class A {
public class Operazioni {
Operazioni() { if(b == null) throw new IllegalStateException("b non è definito"); }
public void operazione1SuB() { System.out.println(b.toString()); }
public void operazione2SuB() { System.out.println(b.hashCode()); }
public void operazioneNSuB() { System.out.println(b.getClass()); }
}
private B b;
private Operazioni op;
public void setB(B b) { this.b = b; }
public Operazioni op() { return op == null ? op = new Operazioni() : op; }
}
Oppure potremmo pensare ad a come un operatore unario su valori di tipo b. Essendo unario, almeno un b bisogna passarglielo. Codice:
class A {
public void operazione1SuB(B b) { System.out.println(b.toString()); }
public void operazione2SuB(B b) { System.out.println(b.hashCode()); }
public void operazioneNSuB(B b) { System.out.println(b.getClass()); }
}
Codice:
import java.util.LinkedList;
import java.util.List;
public class Prova {
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println("esecuzione senza 'set'");
a.operazione();
b.operazione();
a.add(b);
b.add(a);
System.out.println("esecuzione col 'set'");
a.operazione();
b.operazione();
}
}
class A {
private List<B> listeners = new LinkedList<B>();
void add(B b) { listeners.add(b); }
void operazione() {
for (B b : listeners) b.notifica(this);
}
void notifica(B b) {
System.out.println("A riceve una notifica di un evento prodotto da " + b);
}
}
class B {
private List<A> listeners = new LinkedList<A>();
void add(A a) { listeners.add(a); }
void operazione() {
for(A a : listeners) a.notifica(this);
}
void notifica(A a) {
System.out.println("B riceve una notifica di un evento prodotto da " + a);
}
}
Con un po' di immaginazione si possono trovare anche altre soluzioni. |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 22:13.




















