vierseitig

Werbung
2. JavaBeans als Komponenten
•
•
•
•
•
Hintergrund und Motivation
Java-GUI-Elemente sind Beans
Typischer Aufbau von Beans
Bound properties
Constrained Properties
Speichern
• JavaBeans sind als frühes Komponentenmodell entstanden
• Objekte einfach serialisierbar (damit einfach im Netz
austauschbar)
• Beans-Framework ermöglicht einfache Kommunikation
unter Beans
• Haupteinsatz: GUI-Komponenten, Swing nutzt Technologie
(ermöglicht u. a. GUI-Builder [gute/schlechte])
• Aktuelle Spezifikation: JavaBeans 1.01
• Ideen für JavaBeans Spec 2.0 (JSR-273) existieren/ ruhen
• Zitat: “A Java Bean is a reusable software component that
can be manipulated visually in a builder tool.”
• Achtung: nicht mit Enterprise JavaBeans verwechseln
Literatur:
• Sun, JavaBeans 1.01 Specification, http://java.sun.com/
javase/technologies/desktop/javabeans/docs/spec.html
• C. Ullenboom, Java ist auch eine Insel, 8. Auflage, Galileo
Press [Abschnitt 7.4]
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
54
Erinnerung: JButton (Nutzung)
public ButtonFrame()
ButtonFrame() {
setSize(200, 100);
JButton rot = new JButton("rot");
JButton("rot");
rot.addActionListener(new MeineAction(getContentPane(),
MeineAction(getContentPane(),
Color.RED));
Color.RED));
add(rot,
add(rot, BorderLayout.EAST);
BorderLayout.EAST);
JButton blau = new JButton("blau");
JButton("blau");
blau.addActionListener(new MeineAction(getContentPane(),
MeineAction(getContentPane(),
Color.BLUE));
Color.BLUE));
add(blau,
add(blau, BorderLayout.WEST);
BorderLayout.WEST);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String args[])
args[]) {
java.awt.EventQueue.invokeLater(new Runnable()
Runnable() {
public void run()
run() {new
{new ButtonFrame().setVisible(true);}
ButtonFrame().setVisible(true);}
});
}
Entwicklung
Prof. Dr.
Stephan Kleuker
Prof. Dr.
Stephan Kleuker
55
Erinnerung: JButton (ActionListener)
public class ButtonFrame extends JFrame {
} Komponentenbasierte Software-
Komponentenbasierte SoftwareEntwicklung
import
import
import
import
public class MeineAction implements ActionListener {
private Component komponente;
komponente;
private Color farbe;
farbe;
public MeineAction(Component komponente,
komponente, Color farbe){
farbe){
this.komponente = komponente;
komponente;
this.farbe = farbe;
farbe;
}
}
56
java.awt.Color;
java.awt.Color;
java.awt.Component;
java.awt.Component;
java.awt.event.ActionEvent;
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
java.awt.event.ActionListener;
public void actionPerformed(ActionEvent e) {
komponente.setBackground(farbe);
komponente.setBackground(farbe);
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
57
Typische Beanmethoden (1/2)
Typische Beanmethoden (2/2)
public class Knopf {
public static void main(String[]
main(String[] s){
JButton jb=
jb= new JButton();
JButton();
jb.addPropertyChangeListener(new PCL());
jb.setText("touch me");
me");
jb.setToolTipText("bin ne Bean");
Bean");
jb.setBackground(Color.red);
jb.setBackground(Color.red);
jb.setBorderPainted(false);
jb.setBorderPainted(false);
JFrame jf = new JFrame();
JFrame();
jf.addPropertyChangeListener(new PCL());
jf.add(jb);
jf.add(jb);
jf.setSize(200, 100);
jf.setTitle("Knopf");
jf.setTitle("Knopf");
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
);
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE
jf.setVisible(true);
jf.setVisible(true);
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
public class PCL implements PropertyChangeListener{
PropertyChangeListener{
public PCL() {}
public void propertyChange(PropertyChangeEvent evt)
evt) {
System.out.println(evt.getPropertyName()
System.out.println(evt.getPropertyName()
+" alt:"+evt.getOldValue()
alt:"+evt.getOldValue()
+" neu:"+evt.getNewValue());
neu:"+evt.getNewValue());
} text alt: neu:touch me
}
ToolTipText alt:null neu:bin ne Bean
background alt:javax.swing.plaf.ColorUIResource[r=238,...
borderPainted alt:true neu:false
title alt: neu:Knopf
defaultCloseOperation alt:1 neu:3
foreground alt:null neu:java.awt.Color[r=0,g=0,b=0]
font alt:null neu:java.awt.Font[family=Dialog,name=Dia...
neu:java.awt.Font[family=Dialog,name=Dia...
ancestor alt:null neu:javax.swing.JPanel[null.contentP...
neu:javax.swing.JPanel[null.contentP...
58
Elementare Anforderungen an JavaBean
public void setXx(<Typ>
setXx(<Typ> xx)
xx) {
this.xx = xx;
xx;
}
public <Typ> getXx()
getXx() {
xx;
return xx
;
}
• Methoden können weiteren Code enthalten
• Jedwede Typen von Variablen sind serialisierbar
Prof. Dr.
Stephan Kleuker
Prof. Dr.
Stephan Kleuker
59
Minimales Beispiel
• Default-Konstruktor (keine Parameter)
• Alle Exemplarvariablen (Properties, Attribute) über get- und
set-Methoden erreichbar
• Variable private <Typ> xx;
xx;
Komponentenbasierte SoftwareEntwicklung
Komponentenbasierte SoftwareEntwicklung
60
import java.io.Serializable;
java.io.Serializable;
public class Student implements Serializable{
Serializable{
private String name;
name;
private int cp;
cp;
public Student(){}
public int getCp()
getCp() {
return cp;
cp;
}
public void setCp(int cp)
cp) {
this.cp = cp;
cp;
}
public String getName()
getName() {
return name;
name;
}
public void setName(String name)
name) {
this.name = name;
name;
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
61
Einschub: typischer schlechter Stil
Indizierte Eigenschaften
• Für Eigenschaften, die in Arrays gespeichert werden,
besteht zusätzlich folgende Möglichkeit (Ausschnitt)
• Arrays sind für dynamische Datenmengen unflexibel
• Collections sind auch nutzbar (auch serialisierbar)
private String[] vorlesung;
vorlesung;
public String[] getVorlesung()
getVorlesung() { //bekannt
return vorlesung;
vorlesung;
}
public void setVorlesung(String[]
setVorlesung(String[] vorlesung)
vorlesung) { //bekannt
this.vorlesung = vorlesung;
vorlesung;
}
public String getVorlesung(int index)
index) {
return vorlesung[index];
vorlesung[index];
}
public void setVorlesung(String vl,
vl, int index)
index) {
vorlesung[index]=vl;
vorlesung[index]=vl;
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
private Set<String>
Set<String> vorlesung=
vorlesung= new HashSet<String>();
HashSet<String>();
mit üblichen get- und set-Methoden
• In JavaBeans können weitere Methoden ergänzt werden
public void weitereVorlesung(String v){
vorlesung.add(v);
vorlesung.add(v);
}
• Leider nicht unüblich der Stil „Innereien herausreißen,
verändern, Innereien wieder hinschieben“ (verletzt
eigentlich Geheimnisprinzip)
Student st = new Student();
st.getVorlesung().add("KomSE");
");
st.getVorlesung().add("KomSE
62
Gebundene Eigenschaften
63
import java.beans.PropertyChangeListener;
java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
java.beans.PropertyChangeSupport;
…
private PropertyChangeSupport pcs=new PropertyChangeSupport(this);
PropertyChangeSupport(this);
public void setCp(int cp)
cp) {
int alt=this.cp;
alt=this.cp;
this.cp = cp;
cp;
pcs.firePropertyChange("cp",
pcs.firePropertyChange("cp", alt, cp);
cp);
}
public void addPropertyChangeListener(PropertyChangeListener l){
pcs.addPropertyChangeListener(l);
pcs.addPropertyChangeListener(l);
}
• Interessenten für Änderungen müssen sich mit add…
anmelden
• Bei Anmeldung muss Objekt übergeben werden, das das
Interface PropertychangeEvent implementiert
• normales Observer-Observable-Pattern
Prof. Dr.
Stephan Kleuker
Prof. Dr.
Stephan Kleuker
Beispiel-Erweiterung in Student (1/2)
• Bound properties sind Exemplarvariablen, die Änderungen
interessierten Beans mitteilen (Observer-Observable)
• Wer Änderungen mitteilen will,
– benötigt Objekt der Klasse PropertyChangeSupport
– muss Methoden add/removePropertyChangeListener
implementieren
Komponentenbasierte SoftwareEntwicklung
Komponentenbasierte SoftwareEntwicklung
public void removePropertyChangeListener
removePropertyChangeListener(
(
PropertyChangeListener l){
pcs.removePropertyChangeListener(l);
pcs.removePropertyChangeListener(l);
}
64
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
65
Beispiel-Erweiterung in Student (2/2)
Veto-Eigenschaften
import java.beans.PropertyChangeListener;
java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
java.beans.PropertyChangeEvent;
public class Studentnutzer {
public static void main(String[]
main(String[] args)
args) {
Student s = new Student();
s.addPropertyChangeListener(new PropertyChangeListener()
PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
System.out.println("Eigenschaft "+e.getPropertyName
"+e.getPropertyName()
e.getPropertyName()
+" alt:"+e.getOldValue()+"
alt:"+e.getOldValue()+" neu:"+e.getNewValue());
neu:"+e.getNewValue());
}
});
s.setCp(42);
s.setCp(s.getCp()+5);
s.setCp(47);
Eigenschaft cp alt:0 neu:42
}
Eigenschaft cp alt:42 neu:47
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
66
Constrained und Bound
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
67
Beispiel ohne Bound Property (1/3)
private VetoableChangeSupport vcs=new
vcs=new VetoableChangeSupport(this);
VetoableChangeSupport(this);
public void setVorlesung(Set<String>
setVorlesung(Set<String> vorlesung)
vorlesung) {
Set<String>
Set<String> old = this.vorlesung;
this.vorlesung;
in Student
try {
vcs.fireVetoableChange("vl",
vcs.fireVetoableChange("vl", old,
old, vorlesung);
vorlesung);
this.vorlesung = vorlesung;
vorlesung;
} catch (PropertyVetoException
(PropertyVetoException ex) {
System.out.println("abgelehnt:
System.out.println("abgelehnt: "+ex.getMessage
"+ex.getMessage());
ex.getMessage());
}
}
• Listener für eine vetoable Property erhalten Änderung mit
public void vetoableChange(PropertyChangeEvent e)
• gibt e.getNewValue()
e.getNewValue() e.getOldValue()
e.getOldValue() e.getPropertyName()
e.getPropertyName()
• Problem: Listener macht kein Veto und rechnet mit Daten
weiter, aber anderer Listener hat Veto (vgl. dirty read)
• sauberer Ansatz, bei versuchter Änderung
– erst nach Vetos fragen
– wenn Veto, dann Änderung abbrechen
– wenn kein Veto, dann Änderung als bound property
behandeln (propertyChange), also zwei Listener
zusammen
• sauberes Beispiel: s. Praktikum
• schmuddeliges Beispiel: nächste Folien
• Anmerkung: Parameterinhalte kann man ändern
Komponentenbasierte SoftwareEntwicklung
• Spezielle Möglichkeit von JavaBeans: Vetoable (constrained)
– Bean meldet angemeldeten Beans, dass eine
Exemplarvariable geändert wird
– Jede Bean kann „Einspruch“ gegen die Änderung
(PropertyVetoException) einlegen
• Konkretes Szenario: Kundenbestellung soll durchgeführt
werden, Kontoverwaltung und Lagerverwaltung lauschen und
können Einspruch einlegen
• Nach Einspruch werden alle angemeldeten Beans erneut mit
altem Wert informiert
Prof. Dr.
Stephan Kleuker
public void addVetoableChangeListener(VetoableChangeListener l){
vcs.addVetoableChangeListener(l);
vcs.addVetoableChangeListener(l);
}
public void removeVetoableChangeListener
removeVetoableChangeListener(
(
VetoableChangeListener l) {
vcs.removeVetoableChangeListener(l);
vcs.removeVetoableChangeListener(l);
}
68
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
69
Beispiel ohne Bound Property (2/3)
Beispiel ohne Bound Property (3/3)
public class MeinVeto implements VetoableChangeListener{
VetoableChangeListener{
private String schlecht;
private int aenderung;
aenderung;
public MeinVeto(String schlecht) {
this.schlecht = schlecht;
}
@Override
public void vetoableChange(PropertyChangeEvent evt)
evt)
throws PropertyVetoException {
Set<String>
Set<String> neu = (Set<String
(Set<String>)
Set<String>) evt.getNewValue();
evt.getNewValue();
if (neu.contains(schlecht))
neu.contains(schlecht))
throw new PropertyVetoException("nicht "+schlecht, evt);
evt);
System.out.println("fü
System.out.println("für "+schlecht+": "+(++aenderung
"+(++aenderung));
aenderung));
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
70
Wesentlicher Nachrichtenfluss
stu:Student (+vcs)
setVorlesung
((C,Java))
:MeinVeto(BWL)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
71
Einfaches Speichern (von JavaBeans)
public static void main(String[]
main(String[] args)
args) {
Student stu = new Student();
HashSet<String>
HashSet<String> vls = new HashSet();
HashSet();
vls.add("C");
vls.add("C");
vls.add("Java");
vls.add("Java");
stu.setVorlesung(vls);
stu.setVorlesung(vls); stu.setName("Erwin");
stu.setName("Erwin");
try {
XMLEncoder out = new XMLEncoder(new BufferedOutputStream(
BufferedOutputStream(
new FileOutputStream("stu.xml")));
FileOutputStream("stu.xml")));
out.writeObject(stu);
out.writeObject(stu);
out.close();
out.close();
XMLDecoder in= new XMLDecoder(new BufferedInputStream(
BufferedInputStream(
new FileInputStream("stu.xml")));
FileInputStream("stu.xml")));
Student st= (Student)in.readObject
(Student)in.readObject();
Student)in.readObject();
System.out.println(st.getVorlesung());
System.out.println(st.getVorlesung());
in.close();
in.close();
} catch (FileNotFoundException
(FileNotFoundException ex) { }
[C, Java]
}
:MeinVeto(C++)
fireVetoableChange
BWL:1
(vl,null,(C,Java))
fireVetoableChange (vl,null,(C,Java))
C++:1
vorlesung=(C,Java)
vorlesung=(C,Java)
setVorlesung
((C,Java,C++))
public static void main(String[]
main(String[] args)
args) {
Student stu = new Student();
Set<String>
Set<String> vls = new HashSet();
HashSet();
vls.add("C");
vls.add("C");
vls.add("Java");
vls.add("Java");
stu.addVetoableChangeListener(new MeinVeto("BWL"));
MeinVeto("BWL"));
stu.addVetoableChangeListener(new MeinVeto("C++"));
MeinVeto("C++"));
stu.setVorlesung(vls);
stu.setVorlesung(vls);
Set<String>
Set<String> tmp = (Set<String>)vls.clone
(Set<String>)vls.clone();
Set<String>)vls.clone();
für BWL: 1
tmp.add("C++");
tmp.add("C++");
für C++: 1
stu.setVorlesung(tmp);
stu.setVorlesung(tmp);
System.out.println(stu.getVorlesung());
System.out.println(stu.getVorlesung()); für BWL: 2
}
für BWL: 3
für C++: 2
abgelehnt: nicht C++
[C, Java]
fireVetoableChange
BWL:2
(vl,(C,Java),(C,Java,C++))
fireVetoableChange(vl,(C,Java),(C,Java,C++))
PropertyVetoException
fireVetoableChange
BWL:3
(vl,(C,Java,C++),(C,Java))
fireVetoableChange(vl,(C,Java,C++),(C,Java))
C++:2
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
72
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
73
stu.xml
Analyse des Beispiels
<?xml
<?xml version="1.0" encoding="UTFencoding="UTF-8"?>
<java version="1.6.0_12" class="java.beans.XMLDecoder">
class="java.beans.XMLDecoder">
<object class="beans.Student">
class="beans.Student">
<void property="name">
property="name">
<string>Erwin</string>
string>Erwin</string>
</void
</void>
void>
<void property="vorlesung">
property="vorlesung">
<void method="add">
method="add">
<string>C</string>
string>C</string>
</void
</void>
void>
<void method="add">
method="add">
<string>Java</string>
string>Java</string>
</void
</void>
void>
</void
</void>
void>
</object
</object>
object>
</java
</java>
java>
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
• Wesentliche Funktionalität wurde an Java (genauer die
Virtual Machine VM) abgegeben; diese arbeitet als
Container
• VM kann direkt auf Exemplarvariablen zugreifen (Ansätze
mit Introspection, Reflection)
– Gib mir Exemplarvariablen
– Gib mir Exemplarmethoden
– (Textanalyse, Beginn mit get/set)
– Rufe auf Objekt mit Methode mit Namen … und
Parametern … auf
74
Weiterführend
• Zu jeder Bean kann es eine
BeanInfo-Klasse geben, die
die Bean beschreibt
• Ursprünglich sind Beans für
visuelle Komponenten
entwickelt worden; GUIBuilder erlauben die direkte
Bearbeitung von Properties
• Java-Bean für GUI-Builder in jar-Datei mit Manifest-Datei
(.mf)
• Es gibt eigene Werkzeuge zur Entwicklung mit Beans
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
76
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
75
Herunterladen