Originariamente inviata da
filograndipad2
Potresti scrivere delle semplici e chiare linee di codice di esempio dove è possibile cogliere tutta la questione? Nel post precedente facevo l'esempio della classse Cane e di quella Padrone giusto per scrivere qualcosa di concreto.
Nel tuo esempio iniziale, Padrone e Cane, dicevi "quando l'animale ha fame". Ma l'animale sarà un oggetto, no? E non ha vita autonoma, nel senso che come oggetto sarà "usato" e pilotato (con metodi) da altre entità. Quindi quando è che DA SOLO (senza che il Padrone faccia qualcosa) l'animale arriva ad uno stato da avere fame? Ci sarebbero da considerare diverse cose ....
Ti faccio invece un altro esempio, facilmente comprensibile: l'automobile e il cruscotto. Si vuole che il cruscotto mostri delle informazioni (io farò dei banali System.out.println) quando "qualcosa" cambia nello stato della automobile.
Innanzitutto definisco la interface Java che rappresenta il "contratto" tra l'automobile e chi vuole ricevere le notifiche:
codice:
public interface AscoltatoreAutomobile {
void macchinaAccesa();
void macchinaSpenta();
void marciaCambiata(int marcia);
void marciaInFolle();
}
Poi scrivo l'Automobile, che "sa" di 1 solo possibile oggetto "ascoltatore" (AscoltatoreAutomobile):
codice:
public class Automobile {
private boolean accesa;
private int marcia;
private AscoltatoreAutomobile ascoltatore;
public Automobile() {
accesa = false; // inizialmente spenta
marcia = 0; // "folle"
}
public void setAscoltatore(AscoltatoreAutomobile ascoltatore) {
this.ascoltatore = ascoltatore;
}
public void accendi() {
if (!accesa) {
accesa = true;
if (ascoltatore != null) {
ascoltatore.macchinaAccesa();
}
}
}
public void spegni() {
if (accesa) {
accesa = false;
if (ascoltatore != null) {
ascoltatore.macchinaSpenta();
}
}
}
public void aumentaMarcia() {
if (marcia < 5) {
marcia++;
if (ascoltatore != null) {
ascoltatore.marciaCambiata(marcia);
}
}
}
public void scalaMarcia() {
if (marcia > 1) {
marcia--;
if (ascoltatore != null) {
ascoltatore.marciaCambiata(marcia);
}
}
}
public void impostaMarciaFolle() {
if (marcia != 0) {
marcia = 0;
if (ascoltatore != null) {
ascoltatore.marciaInFolle();
}
}
}
}
Quindi il Cruscotto che come si vede qui sotto, è una semplice e banale implementazione di AscoltatoreAutomobile:
codice:
public class Cruscotto implements AscoltatoreAutomobile {
@Override
public void macchinaAccesa() {
System.out.println("ACCESA");
}
@Override
public void macchinaSpenta() {
System.out.println("SPENTA");
}
@Override
public void marciaCambiata(int marcia) {
System.out.println("MARCIA " + marcia);
}
@Override
public void marciaInFolle() {
System.out.println("MARCIA IN 'FOLLE'");
}
}
Poi un piccolo main di prova:
codice:
public class ProvaAutomobile {
public static void main(String[] args) {
Automobile automobile = new Automobile();
Cruscotto cruscotto = new Cruscotto();
automobile.setAscoltatore(cruscotto);
automobile.accendi();
automobile.accendi(); // non fa nulla e non notifica nulla
automobile.aumentaMarcia();
automobile.aumentaMarcia();
automobile.scalaMarcia();
automobile.spegni();
automobile.impostaMarciaFolle();
}
}
Come si vede nel main, viene invocato setAscoltatore passando direttamente l'oggetto Cruscotto. Cruscotto implementa AscoltatoreAutomobile quindi per il compilatore è perfettamente lecito.
Il punto importante è che Automobile non "sa" nulla di Cruscotto e viceversa Cruscotto non "sa" nulla di Automobile! Grazie alla interfaccia che fa da "contratto" per la notifica, le due entità sono completamente disaccoppiate.
Tutto questo, come ho detto prima, NON è un Observer in senso stretto, né un listener inteso come quelli di AWT/Swing. È semplicemente l'uso basilare della programmazione ad oggetti, in questo caso l'uso di una interfaccia, per applicare un meccanismo di notifica (o "callback").
P.S. il codice è perfettamente compilabile e provabile. Verificalo pure.