Java Standard: Muster Observer
Aus Wikibooks
Inhaltsverzeichnis |
[Bearbeiten] Beobachter
Informiert über Änderungen eines Objektes (vergleiche WikiBook Muster).
[Bearbeiten] Implementierung (1) - do it yourself
import java.util.ArrayList; public class Subjekt { private ArrayList<Beobachter> beobachter = new ArrayList<Beobachter>(); private Object zustand = null; private void benachrichtigen() { for (Beobachter b : beobachter) b.aktualisiere(); } public void entferne(Beobachter b) { beobachter.remove(b); } public Object gibZustand() { return zustand; } public void registriere(Beobachter b) { beobachter.add(b); } public void setzeZustand(Object neu) { zustand = neu; benachrichtigen(); } }
public interface Beobachter { public void aktualisiere(); }
public class KonsolenBeobachter implements Beobachter { protected Subjekt subjekt = null; public void setzeSubjekt(Subjekt s) { if (this.subjekt != null) this.subjekt.entferne(this); this.subjekt = s; if (this.subjekt != null) this.subjekt.registriere(this); } public void aktualisiere() { System.out.println(this.subjekt.gibZustand()); } }
public class GeschwaetzigerKonsolenBeobachter extends KonsolenBeobachter { public void aktualisiere() { System.out.println("Das Subjekt hat seinen Zustand geaendert; jetzt: " + this.subjekt.gibZustand()); } }
public class BeobachterTest { public static void main(String[] args) { Subjekt s = new Subjekt(); KonsolenBeobachter b1 = new KonsolenBeobachter(); KonsolenBeobachter b2 = new GeschwaetzigerKonsolenBeobachter(); b1.setzeSubjekt(s); b2.setzeSubjekt(s); s.setzeZustand("Hallo Welt"); b2.setzeSubjekt(null); s.setzeZustand("Hallo schoene Welt"); } }
[Bearbeiten] Implementierung (2) - java.util.Observer, java.util.Observable
public class Beobachter implements Observer {
private static int NR = 1;
private int nr;
public Beobachter() {
this.nr = Beobachter.NR++;
}
public void update(Observable beobachtbarer, Object text) {
System.out.println("Beobachter " + nr + " meldet: Text=" + text);
}
}
public class Beobachtbarer extends Observable {
private String text;
public Beobachtbarer() {
super();
}
public void setText(String text) {
this.text = text;
super.setChanged(); // Markierung, daß sich der Text geändert hat
super.notifyObservers(text); // ruft für alle Beobachter die update-Methode auf
}
public String getText() {
return text;
}
}
public class Beobachtungen {
public static void main(String[] args) {
Beobachter[] bArray = {new Beobachter(), new Beobachter(), new Beobachter()};
Beobachtbarer bb = new Beobachtbarer();
for (Beobachter b: Arrays.asList(bArray)) {
bb.addObserver(b);
}
bb.setText("Ich");
bb.setText("werde");
bb.setText("beobachtet.");
}
}
/* Ausgabe: ******** Beobachter 3 meldet: Text=Ich Beobachter 2 meldet: Text=Ich Beobachter 1 meldet: Text=Ich Beobachter 3 meldet: Text=werde Beobachter 2 meldet: Text=werde Beobachter 1 meldet: Text=werde Beobachter 3 meldet: Text=beobachtet. Beobachter 2 meldet: Text=beobachtet. Beobachter 1 meldet: Text=beobachtet. */
[Bearbeiten] Erläuterungen
Ein Observer (Beobachter) kann über seine update-Methode auf Änderungen eines Observable (Beobachtbarer) reagieren. Das passiert jedoch nur, wenn sich Observer an Observable registrieren.
In unserer Beispiel-Implementierung wird in der update-Methode von Beobachter lediglich eine Info auf die Konsole geschrieben. Die Klasse Beobachtbarer besitzt nur eine Set-Methode, über die ein Text verändert werden kann. Dabei wird der geänderte Text immer mittels der setChanged-Methode als "geändert" markiert und über die notifyObservers-Methode wird bei allen registrierten Observer-Objekten die update-Methode aufgerufen.
Die zentrale Klasse Beobachtungen vereint nun Observer und Observable. Wir sind maßlos und haben gleich drei Beobachter bei dem Beobachtbarer registriert. Jeder Aufruf der setText-Methode bewirkt nun den Aufruf der update-Methode bei allen drei Beobachter-Objekten.
[Bearbeiten] Implementierung (3) - java.beans.PropertyChangeListener / java.beans.PropertyChangeSupport
public class AktualisierungsListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent pce) {
System.out.println("Bei der " + pce.getSource() + " wurde der Parameter \"" +
pce.getPropertyName() + "\" von \"" + pce.getOldValue() +
"\" auf \"" + pce.getNewValue() + "\" geaendert.");
}
}
public class Quelle {
private String text;
private int zahl;
public void setText(String text) {
this.text = text;
}
public void setZahl(int zahl) {
this.zahl = zahl;
}
public String getText() {
return text;
}
public int getZahl() {
return zahl;
}
public String toString() {
return "Quell-Bean";
}
}
public class Aktualisierbarer extends PropertyChangeSupport {
private Quelle quelle;
public Aktualisierbarer(Quelle quelle) {
super(quelle);
this.quelle = quelle;
}
public void setText(String text) {
super.firePropertyChange("text", quelle.getText(), text);
quelle.setText(text);
}
public void setZahl(int zahl) {
super.firePropertyChange("zahl", quelle.getZahl(), zahl);
quelle.setZahl(zahl);
}
public String getText() {
return quelle.getText();
}
public int getZahl() {
return quelle.getZahl();
}
}
public class Aktualisierungen {
public static void main(String[] args) {
Aktualisierbarer aktu = new Aktualisierbarer(new Quelle());
aktu.addPropertyChangeListener(new AktualisierungsListener());
aktu.setZahl(7);
aktu.setText("vorher");
aktu.setText("jetzt");
aktu.setZahl(13);
}
}
/* Ausgabe: ******** Bei der Quell-Bean wurde der Parameter "zahl" von "0" auf "7" geaendert. Bei der Quell-Bean wurde der Parameter "text" von "null" auf "vorher" geaendert. Bei der Quell-Bean wurde der Parameter "text" von "vorher" auf "jetzt" geaendert. Bei der Quell-Bean wurde der Parameter "zahl" von "7" auf "13" geaendert. */
[Bearbeiten] Erläuterungen
Über den AktualisierungsListener werden die Inhaltsänderungen von Objekten (hier: Quell-Bean) überwacht und es kann darauf reagiert werden. In unserem Beispiel wird hier lediglich eine Ausgabe auf die Konsole gemacht.
Unsere Quelle (Quell-Bean) besitzt 2 Attribute, die gesetzt werden können. Mit dem Aktualisierbarer werden diese Setz-Möglichkeiten überwacht. In jeder seiner Set-Methoden wird ein Attribut-Änderungs-Event ausgelöst.
Die zentrale Klasse Aktualisierungen vereint nun AktualisierungsListener und Aktualisierbarer, damit die Attribut-Änderungen der Quell-Bean auch bemerkt werden.

