Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Download: - ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /Java-Insel | vor >>
Java ist auch eine Insel von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel 7., aktualisierte Auflage geb., mit DVD (November 2007) 1.492 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1146-8 |
| 7 Angewandte Objektorientierung
|  | 7.1 Schnittstellen in der Anwendung
|  |  | 7.1.1 CharSequence als Beispiel einer Schnittstelle
|  |  | 7.1.2 Die Schnittstelle Iterable
|  |  | 7.1.3 Funktionszeiger
|  |  | 7.1.4 Implementierung einer verketteten Liste
|  | 7.2 Design-Pattern (Entwurfsmuster)
|  |  | 7.2.1 Design-Pattern
|  |  | 7.2.2 Das Beobachter-Pattern (Observer/Observable)
|  |  | 7.2.3 Ereignisse über Listener
|  |  | 7.2.4 Multicast und Unicast
|  | 7.3 JavaBean
|  |  | 7.3.1 Properties (Eigenschaften)
|  |  | 7.3.2 Einfache Eigenschaften
|  |  | 7.3.3 Indizierte Eigenschaften
|  |  | 7.3.4 Gebundene Eigenschaften
|  |  | 7.3.5 Veto-Eigenschaften – dagegen!
## 7.3 JavaBean Unter der JavaBean-Architektur versteht Sun ein einfaches Komponenten-Modell. Beans kommen in allen Ecken der Java-Bibliothek vor, in grafischen Oberflächen, bei Servlets, bei der Persistenz (Abbildung der Objekte in relationale Datenbanken oder XML-Dokumenten), und weiteren Einsatzgebieten. Im Kern basieren JavaBeans auf: Selbstbeobachtung (Introspection). Eine Klasse lässt sich von außen auslesen. So kann ein spezielles Programm, wie ein GUI-Builder oder eine visuelle Entwicklungsumgebung, eine Bean analysieren und ihre Eigenschaften abfragen. Auch umgekehrt kann eine Bean herausfinden, ob sie etwa gerade von einem grafischen Entwicklungswerkzeug modelliert wird oder in einer Applikation ohne GUI Verwendung findet. Eigenschaften (Properties). Attribute beschreiben den Zustand des Objekts. In einem Modellierungswerkzeug lassen sich diese ändern. Da eine Bean zum Beispiel eine grafische Komponente sein kann, hat sie etwa eine Hintergrundfarbe. Diese Informationen können von außen durch bestimmte Methoden abgefragt und verändert werden. Für alle Eigenschaften werden spezielle Zugriffsmethoden definiert; sie werden Property-Design-Pattern genannt. Ereignissen (Events). Komponenten können Ereignisse auslösen, die Zustandsänderungen oder Programmteile weiterleiten können. Anpassung (Customization). Der Bean-Entwickler kann die Eigenschaften einer Bean visuell und interaktiv anpassen. Speicherung (Persistenz). Jede Bean kann ihren internen Zustand, also die Eigenschaften, durch Serialisierung speichern und wiederherstellen. So kann ein Builder-Tool die Komponenten laden und benutzen. Ein spezieller Externalisierungsmechanismus erlaubt dem Entwickler die Definition eines eigenen Speicherformats, zum Beispiel als XML-Datei. Zusätzlich zu diesen notwendigen Grundpfeilern lässt sich durch Internationalisierung die Entwicklung internationaler Komponenten vereinfachen. Verwendet eine Bean länderspezifische Ausdrücke wie Währungsformate oder Datumsformate, kann der Bean-Entwickler mit länderunabhängigen Bezeichnern arbeiten, die dann in die jeweilige Landessprache übersetzt werden. ### 7.3.1 Properties (Eigenschaften) Properties einer JavaBean steuern den Zustand des Objektes. Bisher hat Java keine spezielle Schreibweise für Properties – anders als C# und andere Sprachen –, und so nutzt es eine spezielle Namensgebung bei den Methoden, um Eigenschaften zu lesen und zu schreiben. Der JavaBeans-Standard unterscheidet vier Arten von Properties: Einfache Eigenschaften. Hat eine Person eine Property »Name« , so bietet die JavaBean die Methoden getName() und setName() an. Indizierte/Indexierte Eigenschaften (engl. indexed properties). Sie werden eingesetzt, falls mehrere gleiche Eigenschaften aus einem Array verwaltet werden. So lassen sich Felder gleichen Datentyps verwalten. Gebundene Eigenschaften (engl. bound properties). Ändert eine Komponente ihr Verhalten, dann kann sie angemeldete Interessenten (Listener) informieren. Eigenschaft mit Vetorecht (engl. veto properties, auch constraint properties beziehungsweise eingeschränkte Eigenschaften genannt). Ihre Benutzung ist in jenen Fällen angebracht, in denen eine Bean Eigenschaften ändern möchte, andere Beans aber dagegen sind und ihr Veto einlegen. Die Eigenschaften der Komponente können primitive Datentypen, aber auch komplexe Klassen sein. Der Text einer Schaltfläche ist ein einfacher String, eine Sortierstrategie in einem Sortierprogramm ist jedoch ein komplexes Objekt. ### 7.3.2 Einfache Eigenschaften Für die einfachen Eigenschaften müssen nur ein Paar von setXXX()- und getXXX()-Methoden eingesetzt werden. Der Zugriff auf eine Objektvariable wird also über Funktionen geregelt. Dies hat den Vorteil, dass ein Zugriffsschutz und weitere Überprüfungen eingerichtet werden können. Soll eine Eigenschaft nur gelesen werden (weil sie sich zum Beispiel regelmäßig automatisch aktualisiert), müssen wir die setXXX()-Methode nicht implementieren. Genauso gut können wir Werte, die außerhalb des erlaubten Wertebereichs unserer Applikation liegen, prüfen und ablehnen. Dazu kann eine Methode eine Exception auslösen. Allgemein sieht dann die Signatur der Methoden für eine Eigenschaft XXX vom Typ T folgendermaßen aus: public T getXXX() public void setXXX( T value ) Ist der Property-Typ ein Wahrheitswert, ist neben der Methode getXXX() eine isXXX()-Methode erlaubt. public boolean isXXX() public void setXXX( boolean value ) ### 7.3.3 Indizierte Eigenschaften Falls eine Bean nur über eine einfache Eigenschaft wie eine primitive Variable verfügt, so weisen die getXXX()-Methoden keinen Parameter und genau einen Rückgabewert auf. Der Rückgabewert hat den gleichen Datentyp wie die interne Eigenschaft. Die setXXX()-Methode besitzt genau einen Parameter des Datentyps dieser Eigenschaft. Eine setXXX()-Methode hat keinen expliziten Rückgabewert. Wenn nun kein atomarer Wert, sondern ein Feld von Werten intern gespeichert ist, müssen wir Zugriff auf bestimmte Werte bekommen. Daher erwarten die setXXX()- und getXXX()-Methoden im zusätzlichen Parameter einen Index: public T[] getXXX() public T getXXX( int index ) public void setXXX( T[] values ) public void setXXX( T value, int index ) ### 7.3.4 Gebundene Eigenschaften Die gebundenen Eigenschaften einer Bean erlauben es, andere Komponenten über eine Zustandsänderung der Properties zu informieren. Bei den gebundenen Eigenschaften (engl. bound properties) geht es ausschließlich um Änderungen der Properties und nicht um andere Ereignisse, die nicht mit den Bean-Eigenschaften zu tun haben. Die Listener empfangen von der Bean ein PropertyChangeEvent, das sie auswerten können. Die Interessenten lassen sich mit addPropertyChangeListener() als Zuhörer einfügen und mit removePropertyChangeListener() abhängen. Bei einer Veränderung werden alle regis-trierten Zuhörer durch ein PropertyChangeEvent informiert. Die Interessierten implementieren dafür PropertyChangeListener. Das Ereignis-Objekt speichert den alten und den neuen Wert sowie den Typ und den Namen der Eigenschaft. Die Zuhörer werden erst nach der Änderung des internen Zustands informiert. Ein Beispiel: Unsere Person-Komponente besitzt eine Property »Name«, die der Setter setName() ändert. Nach der Änderung werden alle Listener informiert. Sie bewirkt sonst nichts Großartiges. Listing 7.16 com/tutego/insel/bean/bound/Person.java
    package com.tutego.insel.bean.bound;

    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;

    public class Person
    {
      private String name = "";

      private PropertyChangeSupport changes = new PropertyChangeSupport( this );

      public void setName( String name )
      {
        String oldName = this.name;
        this.name = name;
        changes.firePropertyChange( "name", oldName, name );
      }

      public String getName()
      {
        return name;
      }
      public void addPropertyChangeListener( PropertyChangeListener l )
      {
        changes.addPropertyChangeListener( l );
      }

      public void removePropertyChangeListener( PropertyChangeListener l )
      {
        changes.removePropertyChangeListener( l );
      }
    }
Der Implementierung setName() kommt zentrale Bedeutung zu. Der erste Parameter von firePropertyChange() ist der Name der Eigenschaft. Er ist für das Ereignis von Belang und muss nicht zwingend der Name der Bean-Eigenschaft sein. Es folgen der alte und der neue Stand des Werts. Die Methode informiert alle angemeldeten Zuhörer über die Änderung mit einem PropertyChangeEvent.
    class java.beans.PropertyChangeSupport
    implements Serializable
PropertyChangeSupport( Object sourceBean ) Konstruiert ein PropertyChangeSupport-Objekt, das sourceBean als auslösende Bean betrachtet. synchronized void addPropertyChangeListener( PropertyChangeListener listener ) Fügt einen Listener hinzu. synchronized void removePropertyChangeListener( PropertyChangeListener listener ) Entfernt einen Listener. synchronized void addPropertyChangeListener( String propertyName, PropertyChangeListener listener ) Fügt einen Listener hinzu, der nur auf Ereignisse mit dem Namen propertyName hört. synchronized void removePropertyChangeListener( String propertyName, PropertyChangeListener listener ) Entfernt den Listener, der auf propertyName hört. void firePropertyChange( String propertyName, Object oldValue, Object newValue ) Informiert alle Listener über eine Werteänderung. Sind alte und neue Werte gleich, werden keine Events ausgelöst. void firePropertyChange( String propertyName, int oldValue, int newValue ) void firePropertyChange( String propertyName, boolean oldValue, boolean newValue ) Varianten von firePropertyChange() mit Integer- und Boolean-Werten. void firePropertyChange( PropertyChangeEvent evt ) Informiert alle Interessenten mit einem PropertyChangeEvent, indem es propertyChange() aufruft. synchronized boolean hasListeners( String propertyName ) Liefert true, wenn es mindestens einen Listener für die Eigenschaft gibt. Angemeldete PropertyChangeListener können auf das PropertyChangeEvent reagieren. Wir testen das an einer Person, die einen neuen Namen bekommt. Listing 7.17 com/tutego/insel/bean/bound/PersonWatcher.java, main()
    Person p = new Person();
    p.addPropertyChangeListener( new PropertyChangeListener()
    {
      @Override public void propertyChange( PropertyChangeEvent e )
      {
        System.out.printf( "Property '%s': '%s' -> '%s'%n",
                           e.getPropertyName(), e.getOldValue(), e.getNewValue() );
      }
    } );
    p.setName( "Ulli" );   // Property 'name': '' -> 'Ulli'
    p.setName( "Ulli" );
    p.setName( "Chris" );  // Property 'name': 'Ulli' -> 'Chris'
Beim zweiten setName() erfolgt kein Event, da es nur dann ausgelöst wird, wenn der Wert wirklich nach der equals()-Methode anders ist.
    interface java.beans.PropertyChangeListener
    extends java.util.EventListener
void propertyChange( PropertyChangeEvent evt ) Wird aufgerufen, wenn sich die gebundene Eigenschaft ändert. Über das PropertyChange-Event erfahren wir die Quelle und den Inhalt der Eigenschaft.
    class java.beans.PropertyChangeEvent
    extends java.util.EventObject
PropertyChangeEvent( Object source, String propertyName, Object oldValue, Object newValue ) Erzeugt ein neues Objekt mit der Quelle, die das Ereignis auslöst, einem Namen, dem alten und dem gewünschten Wert. Die Werte werden intern in privaten Variablen gehalten und lassen sich später nicht mehr ändern. String getPropertyName() Liefert den Namen der Eigenschaft. Object getNewValue() Liefert den neuen Wert. Object getOldValue() Liefert den alten Wert. ### 7.3.5 Veto-Eigenschaften – dagegen! Bei gebundenen Eigenschaften informieren Komponenten andere Komponenten, wenn sich ein Zustand ändert. Möglicherweise haben diese Komponenten jedoch etwas dagegen. In diesem Fall kann ein Zuhörer ein Veto mit einer PropertyVetoException einlegen und so eine Werteänderung verhindern. (Es geht nicht darum, dass die Komponente selbst den Wert ablehnt – es geht um die Interessenten, die das nicht wollen!) Bevor wir die Änderung durchführen, holen wir also die Zustimmung dafür ein. Eine Veto-Eigenschaft ist insofern mit der gebundenen Eigenschaft verwandt, nur dass diese nicht in der Lage ist zu meckern. Programmieren wir eine setXXX()-Methode mit Veto, gibt es im Rumpf vor dem meldenden firePropertyChange() ein fragendes fireVetoableChange(), was die Veto-Listener informiert. Der Veto-Listener kann durch eine ausgelöste PropertyVetoException anzeigen, dass er gegen die Änderung war. Das bricht den Setter ab, und es kommt nicht zum firePropertyChange(). Wegen der PropertyVetoException muss auch die Methode eine Signatur mit throws PropertyVetoException besitzen. In unserem Beispiel darf die Person ein Bigamist sein. Aber natürlich nur dann, wenn es kein Veto gab! Listing 7.18 com/tutego/insel/bean/veto/Person.java
    package com.tutego.insel.bean.veto;

    import java.beans.*;

    public class Person
    {
      private boolean bigamist;

      private PropertyChangeSupport changes = new PropertyChangeSupport( this );
      private VetoableChangeSupport vetos = new VetoableChangeSupport( this );

      public void setBigamist( boolean bigamist ) throws PropertyVetoException
      {
        boolean oldValue = this.bigamist;
        vetos.fireVetoableChange( "bigamist", oldValue, bigamist );
        this.bigamist = bigamist;
        changes.firePropertyChange( "bigamist", oldValue, bigamist );
      }

      public boolean isBigamist()
      {
        return bigamist;
      }

      public void addPropertyChangeListener( PropertyChangeListener l )
      {
        changes.addPropertyChangeListener( l );
      }

      public void removePropertyChangeListener( PropertyChangeListener l )
      {
        changes.removePropertyChangeListener( l );
      }

      public void addVetoableChangeListener( VetoableChangeListener l )
      {
        vetos.addVetoableChangeListener( l );
      }

      public void removeVetoableChangeListener( VetoableChangeListener l )
      {
        vetos.removeVetoableChangeListener( l );
      }
    }
Wie wir an dem Beispiel sehen, ist zusätzlich zum Veto eine gebundene Eigenschaft dabei. Das ist die Regel, damit Interessierte auch mitbekommen, dass die Änderungen für alle gültig wurden. Denn wenn einer der Kandidaten gegen die Änderung ist, dann wird der neue Stand niemals angenommen. Die Interessenten wissen ja nichts voneinander. War jedoch keiner gegen die Änderung, bekommen alle ein PropertyChange und wissen somit, dass alles in Ordnung ist. Alle sind mit dem neuen Wert einverstanden. Beginnen wir zunächst mit einer Person mit einem PropertyChangeListener, der alle gültigen Zustandswechsel meldet. Listing 7.19 com/tutego/insel/bean/veto/PersonWatcher.java, main()
    Person p = new Person();
    p.addPropertyChangeListener( new PropertyChangeListener()
    {
      @Override public void propertyChange( PropertyChangeEvent e )
      {
        System.out.printf( "Property '%s': '%s' -> '%s'%n",
                           e.getPropertyName(), e.getOldValue(), e.getNewValue() );
      }
    } );
Ohne ein Veto gehen alle Zustandsänderungen durch.
    try
    {
      p.setBigamist( true );
      p.setBigamist( false );
    }
    catch ( PropertyVetoException e )
    {
      e.printStackTrace();
    }
Die Ausgabe wird sein:
    Property 'bigamist': 'false' -> 'true'
    Property 'bigamist': 'true' -> 'false'
Nach der Heirat darf unsere Person kein Bigamist mehr sein. Während am Anfang ein Wechsel der Zustände leicht möglich war, ist nach dem Hinzufügen eines Veto-einlegenden Veto-ableChangeListener eine Änderung nicht mehr erlaubt.
    p.addVetoableChangeListener( new VetoableChangeListener()
    {
      @Override
      public void vetoableChange( PropertyChangeEvent e )
        throws PropertyVetoException
      {
        if ( "bigamist".equals( e.getPropertyName() ) )
          if ( (Boolean) e.getNewValue() == true )
            throw new PropertyVetoException( "Nicht mit mir!", e );
      }
    } );
Kern der Logik ist Anweisung throw new PropertyVetoException. Jetzt sind keine unerwünschten Änderungen mehr möglich.
    try
    {
      p.setBigamist( true );
    }
    catch ( PropertyVetoException e )
    {
      e.printStackTrace();
    }
Das setBigamist(true); führt zu einer PropertyVetoException. Der Stack-Trace ist:
    java.beans.PropertyVetoException: Nicht mit mir!
        at com.tutego.insel.bean.veto.PersonWatcher$2.vetoableChange(PersonWatcher.
    java:40)
        at java.beans.VetoableChangeSupport.fireVetoableChange(VetoableChangeSupport.
    java:335)
        at java.beans.VetoableChangeSupport.fireVetoableChange(VetoableChangeSupport.
    java:252)
        at java.beans.VetoableChangeSupport.fireVetoableChange(VetoableChangeSupport.
    java:294)
        at com.tutego.insel.bean.veto.Person.setBigamist(Person.java:19)
        at com.tutego.insel.bean.veto.PersonWatcher.main(PersonWatcher.java:46)
#### Keine transaktionale Sicherheit Gibt es mehrere Listener, die kein Veto einlegen und aus dem Veto-Event das Ergebnis herausnehmen, hat dies den Nachteil, dass ein Listener, der sein Veto einlegt, alles abbricht und die alten Ergebnisse ungültig macht. Glücklicherweise entschuldigt sich dann VetoableChange-Support, indem für die schon abgearbeiteten Listener noch einmal ein Veto mit dem alten Wert geschickt wird. Implementieren wir die Behandlung selbst, so müssen wir den Zustand selbst wiederherstellen und die Hörer informieren. Jetzt dürfen keine Vetos mehr auftauchen. Wenn doch, sollten sie ignoriert werden. Das entspricht einem einfachen Undo. Damit diese Entschuldigung nicht erst beachtet werden muss, reicht es aus, auf die Auslösung von PropertyChange zu warten, um dann sicher zu sein, dass alle das Ergebnis akzeptiert haben. Wenn wir auf ein Veto hören, hat das den Vorteil, dass wir sukzessive den Prozess verfolgen können. Wir können so immer wieder Vorschläge einreichen und sehen, ob sie akzeptiert werden. Obwohl der Wunsch für eine Veto-Änderung auch einen PropertyChange darstellt, ist es fehleranfällig, für Veto- und auch gebundene Eigenschaften gleichzeitig PropertyChangeEvent-Objekte einzusetzen. Während bei Veto-Objekten vor der Zustandsänderung ein PropertyChangeEvent erzeugt wird, informieren die gebundenen Eigenschaften nach der Änderung ihre Zuhörer mit einem PropertyChangeEvent. Daher bedeutet das Aufkommen eines PropertyChangeEvent jeweils etwas Unterschiedliches. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.
Name |
E-Mail |
Ihr Kommentar |
<< zurück | <top> | vor >>

Copyright © Galileo Press 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

[Galileo Computing]
Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de