- Eine Bean hat einen öffentlichen parameterlosen Konstruktor
- Die Bean implementiert Serialisierbarkeit.
- Für die Attribute existieren öffentliche Getter und ggf. auch Setter.
PropertyChange und Veto
Das Besondere an einer Bean ist, dass Änderungen an den Properties durch Ereirgnisse weiterleiten.Ein Attribut kann als Property verwendet werden, wenn es als privates Attribut definiert ist und passende Methoden existieren, die den Zugriff erlauben. Dazu ist konventionsgemäß folgende Benennung erforderlich:
- Das Attribunt ist private und kleingeschrieben, bspw. name
- Die Lesemethode beginnt mit get und es folgt der mit einem Großbuchstaben beginnende Name des Attributs, bspw. getName
- Die Schreibmethode muss nicht implementiert sein. Sie beginnt mit set. Es folgt der Name des Attributs, beginnend mit einem Großbuchstaben. Als Parameter wird der neue Wert des Attributs übergeben.
private String name = "";
public String getName() {
return name;
}
public void setName(String str) {
name = str;
}
Beispiel: Person und Personenkontrolle
Die folgende Bean beschreibt eine Person. Sie hat die Property name, die durch die Methoden getName und setName gelesen und geschrieben werden können.Die Bean bietet Methoden an, um sich als PropertyChangeListener und als VetoableChangeListener einzutragen und wieder abzumelden. Der Unterschied zwischen beiden liegt darin, dass der erstere über eine Änderung der Property informiert wird. Der zweitere kann ein Veto einlegen und eine Änderung durch Werfen einer Exception unterbinden.
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class Person {
private String name = ""; // Diese Eigenschaft soll ueberwacht werden
public static final String NAME_ATTR = "NameAttribute";
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
// Im Setter wird bei einer Aenderung ein Veto angeboten und
// die Aenderung gemeldet.
public void setName(String neuName) throws PropertyVetoException {
String oldName = this.name; // sichere den Bestand
// Informiere die Veto-Maechte, die ggf eine Exception
// ausloesen, um die darauf folgenden Schritte zu vereiteln.
vetos.fireVetoableChange(NAME_ATTR, oldName, neuName);
this.name = neuName; // Die Aenderung erfolgt
// Nun werden die angemeldeten Listener informiert:
changes.firePropertyChange(NAME_ATTR, oldName, neuName);
}
// Der Getter ist voellig unauffaellig
public String getName() {
return name;
}
// Anmeldung fuer Aenderungs-Events des kompletten Objekts
public void addPropertyChangeListener(PropertyChangeListener listener) {
changes.addPropertyChangeListener(listener);
}
// Anmeldung fuer Aenderungs-Events eines speziellen Attributs
public void addPropertyChangeListener(String propStr, PropertyChangeListener listener) {
changes.addPropertyChangeListener(propStr, listener);
}
// Abmeldung
public void removePropertyChangeListener(PropertyChangeListener listener) {
changes.removePropertyChangeListener(listener);
}
// Anmeldung fuer den Widerspruch gegen eine Aenderung
public void addVetoableChangeListener(VetoableChangeListener listener) {
vetos.addVetoableChangeListener(listener);
}
// Abmeldung
public void removeVetoableChangeListener(VetoableChangeListener listener) {
vetos.removeVetoableChangeListener(listener);
}
}
Die folgende Klasse zeigt, wie die Überwachung einer Property-Änderung
funktioniert.
Sie legt sich ein Objekt der Klasse Person an. Darüber meldet sie zunächst
einen ChangeListener an, der hier einfach anzeigt, dass sich etwas geändert
hat.
Im zweiten Schritt meldet sie sich für ein Veto an. Wie oben gesehen wird die Bean dieses Ereignis direkt vor einer Änderung abfeuern. So kann der Überwacher rechtzeitig eine Exception werfen, die eine Änderung verhindert.
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
/**
* Kleines Programm zur Demonstration eines PropertyChangeListeners
*/
public class PersonenKontrolle {
public PersonenKontrolle() {
Person person = new Person();
// Anmelden fuer alle PropertyChangeEvents des Objekts person
person.addPropertyChangeListener(new PropertyChangeListener() {
// Im Falle eines firePropertyChange wird dies aufgerufen:
@Override
public void propertyChange(PropertyChangeEvent e) {
System.out.println(
"Aenderung an: " + e.getPropertyName()
+ "bisher: " + e.getOldValue() + " nun: "
+ e.getNewValue());
}
});
// Anmeldung fuer fireVetoableChange zur Verhinderung einer Aenderung
person.addVetoableChangeListener(new VetoableChangeListener() {
@Override
public void vetoableChange(PropertyChangeEvent e)
throws PropertyVetoException {
if (Person.NAME_ATTR.equals(e.getPropertyName())) {
// Die Eigenschaft NAME_ATTR soll geaendert werden.
String neuName = (String) e.getNewValue();
if (neuName.equals("Kevin")) {
// Die Aenderung soll "Kevin" sein.
// Das muss durch Werfen einer Exception verhindert werden.
throw new PropertyVetoException(
"Alles, nur nicht Kevin!", e);
}
}
}
});
// Nun testen wir die Aenderungs-Listener!
try { // Es kann und wird Exceptions hageln!
person.setName("Martin"); // Aenderung wird gemeldet
person.setName("Martin"); // Keine Aenderung, keine Meldung
person.setName("Kevin"); // Das duerfte am Veto scheitern
person.setName("Matthias"); // Wird wegen der Exception nicht mehr erreicht
} catch (PropertyVetoException e) {
System.out.println(""+e.getMessage()); // Zeige mal den Kommentar!
//e.printStackTrace(); // Komplette Exception darstellen
}
// Tatsächlich: Es bleibt bei Martin!
System.out.println("Name ist nun: " + person.getName());
}
public static void main(String[] args) {
new PersonenKontrolle(); // Starte Instanz!
}
}