Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
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?

Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel

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
Pfeil 7 Angewandte Objektorientierung
Pfeil 7.1 Schnittstellen in der Anwendung
Pfeil 7.1.1 CharSequence als Beispiel einer Schnittstelle
Pfeil 7.1.2 Die Schnittstelle Iterable
Pfeil 7.1.3 Funktionszeiger
Pfeil 7.1.4 Implementierung einer verketteten Liste
Pfeil 7.2 Design-Pattern (Entwurfsmuster)
Pfeil 7.2.1 Design-Pattern
Pfeil 7.2.2 Das Beobachter-Pattern (Observer/Observable)
Pfeil 7.2.3 Ereignisse über Listener
Pfeil 7.2.4 Multicast und Unicast
Pfeil 7.3 JavaBean
Pfeil 7.3.1 Properties (Eigenschaften)
Pfeil 7.3.2 Einfache Eigenschaften
Pfeil 7.3.3 Indizierte Eigenschaften
Pfeil 7.3.4 Gebundene Eigenschaften
Pfeil 7.3.5 Veto-Eigenschaften – dagegen!

Eines der traurigsten Dinge im Leben ist, dass ein Mensch viele gute Taten tun muss, um zu beweisen, dass er tüchtig ist, aber nur einen Fehler zu begehen braucht, um zu beweisen, dass er nichts taugt. – George Bernard Shaw (1856 – 1950)

7 Angewandte Objektorientierung


Galileo Computing - Zum Seitenanfang

7.1 Schnittstellen in der Anwendung Zur nächsten ÜberschriftZur vorigen Überschrift


Galileo Computing - Zum Seitenanfang

7.1.1 CharSequence als Beispiel einer Schnittstelle Zur nächsten ÜberschriftZur vorigen Überschrift

Bisher kennen wir die Klassen String, StringBuffer und StringBuilder, um Zeichenketten zu speichern und weiterzugeben. Ein String ist ein Wertobjekt und ein wichtiges Hilfsmittel in Programmen, da durch ihn unveränderliche Zeichenkettenwerte repräsentiert werden, während StringBuffer und StringBuilder veränderliche Zeichenfolgen umfassen. Aber wie sieht es aus, wenn eine Teilzeichenkette gefordert ist, bei der es egal sein soll, ob das Original als String-, StringBuffer oder StringBuilder-Objekt vorliegt?

Eine Lösung ist, alles in ein String-Objekt zu konvertieren. Möchte ein Programm eine Teilfolge liefern, auf die jemand lesend zugreifen möchte, die er aber nicht verändern können soll, ist ein String zu träge. Aus den beliebigen Zeichenfolgen müsste zuerst ein String-Objekt konstruiert werden. Daher haben die Entwickler seit der Version 1.4 die Schnittstelle CharSequence eingefügt, die eine unveränderliche, nur lesbare Sequenz von Zeichen realisiert. Die Schnittstelle implementieren die Klassen String sowie StringBuffer/StringBuilder. Funktionen müssen sich also nicht mehr für konkrete Klassen entscheiden, sondern können einfach ein CharSequence-Objekt als Argument akzeptieren oder als Rückgabe weitergeben. Ein String und ein StringBuffer/StringBuilder-Objekt können zwar mehr, als CharSequence vorschreibt, beide lassen sich aber als CharSequence einsetzen, wenn das »Mehr« an Funktionalität nicht benötigt wird.

Abbildung 7.1 Einige implementierende Klassen für CharSequence


interface java.lang.CharSequence

  • char charAt( int index ) Liefert das Zeichen an der Stelle index.
  • int length() Gibt die Länge der Zeichensequenz zurück.
  • CharSequence subSequence( int start, int end ) Liefert eine neue CharSequence von start bis end.
  • String toString() Gibt einen String der Sequenz zurück. Die Länge des toString()-Strings entspricht genau der Länge der Sequenz.

Beispiel Beispiel Soll eine Methode eine Zeichenkette bekommen und ist die Herkunft egal, so implementieren wir etwa:

void giveMeAText( CharSequence s ) 
{ 
  ... 
}

anstatt der beiden Funktionen:

void giveMeAText( String s ) 
{ 
  ... 
} 
 
void giveMeAText( StringBuffer s ) 
{ 
  void giveMeAText( new String(s) );  // oder Ähnliches 
}

Anwendung von CharSequence in String

In den Klassen String und StringBuffer/StringBuilder existiert eine Methode subSequence(), die ein CharSequence-Objekt liefert. Die Signatur ist in beiden Fällen die gleiche. Die Funktion macht im Prinzip nichts anderes als ein substring(begin, end).


class java.lang.String implements CharSequence, ... 
class java.lang.StringBuffer implements CharSequence, ... 
class java.lang.StringBuilder implements CharSequence, ...

  • CharSequence subSequence( int beginIndex, int endIndex ) Liefert eine neue Zeichensequenz von String beziehungsweise StringBuffer.

Die Implementierung sieht so aus, dass mit substring() ein neuer Teilstring zurückgeliefert wird. Das ist eine einfache Lösung, aber nicht unbedingt die schnellste. Für String-Objekte ist das Erzeugen von Substrings ziemlich schnell, da die Methode speziell optimiert ist. Da Strings unveränderlich sind, wird einfach das gleiche char-Feld wie im Original-String verwendet, nur eine Verschiebung und ein Längenwert werden angepasst.


Galileo Computing - Zum Seitenanfang

7.1.2 Die Schnittstelle Iterable Zur nächsten ÜberschriftZur vorigen Überschrift

Die erweiterte for-Schleife läuft nicht nur Felder ab, sondern alles, was vom Typ Iterable ist. Die Schnittstelle schreibt für Objekte nur eine Methode iterator() vor, die einen java.util.Iterator liefert, den das for zum Durchlaufen verwendet.


interface java.lang.Iterable<T>

  • Iterator<T> iterator() Liefert einen Iterator, der über alle Elemente vom Typ T iteriert.

Viele Klassen implementieren schon diese Schnittstelle, sodass mit dem erweiterten for durch Ergebnismengen iteriert werden kann. In erster Linie handelt es sich um Datenstrukturen. Dazu kommt noch das Feld, das zwar nicht direkt als Klasse sichtbar ist, aber Iterable passend implementiert.

Einen eigenen Iterable implementieren

Möchten wir selbst rechts neben dem Doppelpunkt vom erweiterten for stehen, müssen wir ein Objekt angeben, dessen Klasse Iterable implementiert und somit eine iterator()-Funktion besitzt. iterator() muss dann einen passenden Iterator zurückgeben. Der wiederum muss die Methoden hasNext() und next() implementieren, um das nächste Element in der Aufzählung anzugeben und das Ende anzuzeigen. Zwar schreibt der Iterator auch remove() vor, doch das wird leer implementiert.

Unser Beispiel soll einen praktischen Iterable implementieren, um über Wörter eines Satzes zu gehen. Als grundlegende Implementierung dient der StringTokenizer, der über has-Token() die nächsten Teilfolgen und über hasMoreTokens() meldet, ob weitere Tokens ausgelesen werden können.

Beginnen wir mit dem ersten Teil, der Klasse WordIterable, die erst einmal Iterable implementieren muss, um auf der rechten Seite vom Punkt stehen zu können. Dann muss dieses Exemplar über iterator() einen Iterator zurückgeben, der über alle Wörter läuft. Dieser Iterator kann als eigene Klasse implementiert werden, doch wir implementieren die Klasse WordIterable so, dass sie Iterable und Iterator gleichzeitig verkörpert; daher ist nur ein Exemplar nötig.

Listing 7.1 com/tutego/insel/iterable/WordIterable.java

package com.tutego.insel.iterable; 
 
import java.util.*; 
 
class WordIterable implements Iterable<String>, Iterator<String> 
{ 
  private StringTokenizer st; 
 
  public WordIterable( String s ) 
  { 
    st = new StringTokenizer( s ); 
  } 
 
  // Method from interface Iterable 
 
  @Override public Iterator<String> iterator() 
  { 
    return this; 
  } 
 
  // Methods from interface Iterator 
 
  @Override public boolean hasNext() 
  { 
    return st.hasMoreTokens(); 
  } 
 
  @Override public String next() 
  { 
    return st.nextToken(); 
  } 
 
  @Override public void remove() 
  { 
    // No remove. 
  } 
}

Im Beispiel:

Listing 7.2 com/tutego/insel/iterable/WordIterableDemo.java, main()

String s = "Am Anfang war das Wort – am Ende die Phrase. (Stanislaw Jerzy Lec)"; 
 
for ( String word : new WordIterable(s) ) 
  System.out.println( word );

Die erweiterte for-Schleife baut der (Eclipse-)Compiler um zu:

Object word; 
WordIterable worditerable; 
for ( Iterator iterator = (worditerable = new WordIterable(s)).iterator(); 
iterator.hasNext(); ) 
{ 
  word = iterator.next(); 
  System.out.println( word ); 
}

Galileo Computing - Zum Seitenanfang

7.1.3 Funktionszeiger Zur nächsten ÜberschriftZur vorigen Überschrift

Das folgende Beispiel implementiert Funktionszeiger über Schnittstellen. Es beginnt mit der Markierungsschnittstelle Operator.

Listing 7.3 com/tutego/insel/functions/Operator.java

package com.tutego.insel.functions; 
 
public interface Operator 
{ 
  // Markierungsschnittstelle 
}

Sie soll Basis-Schnittstelle für Operatoren sein. Von dieser Schnittstelle wollen wir BinaryOperator ableiten, eine Schnittstelle mit einer Operation für zweistellige Operatoren.

Listing 7.4 com/tutego/insel/functions/BinaryOperator.java

package com.tutego.insel.functions; 
 
public interface BinaryOperator extends Operator 
{ 
  double calc( double a, double b ); 
}

Zum Test sollen die Operatoren für + und * implementiert werden:

Listing 7.5 com/tutego/insel/functions/MulOperator.java

package com.tutego.insel.functions; 
 
public class MulOperator implements BinaryOperator 
{ 
  public double calc( double a, double b ) 
  { 
    return a * b; 
  } 
}

Listing 7.6 com/tutego/insel/functions/AddOperator.java

package com.tutego.insel.functions; 
 
public class AddOperator implements BinaryOperator 
{ 
  public double calc( double a, double b ) 
  { 
    return a + b; 
  } 
}

Eine Sammlung von Operatoren speichert ein Operator-Manager. Bei ihm können wir dann über eine Kennung ein Berechnungsobjekt beziehen:

Listing 7.7 com/tutego/insel/functions/OperatorManager.java

package com.tutego.insel.functions; 
 
public class OperatorManager 
{ 
  public final static int ADD = 0; 
  public final static int MUL = 1; 
 
  private static Operator[] operators = { 
    new AddOperator(), 
    new MulOperator() 
  }; 
 
  public static Operator getOperator( int id ) 
  { 
    return operators[ id ]; 
  } 
}

Wenn wir nun einen Operator wünschen, so fragen wir den OperatorManager nach dem passenden Objekt. Die Rückgabe wird ein Operator-Objekt sein, was wir auf BinaryOperator anpassen, da der Basistyp keine Funktionalität ermöglicht. Dann können wir die Funktion calc() aufrufen:

BinaryOperator op = (BinaryOperator) OperatorManager.getOperator(OperatorManager. 
ADD); 
System.out.println( op.calc( 12, 34 ) );

So verbirgt sich hinter jeder ID eine Funktion, die wie ein Funktionszeiger verwendet werden kann. Noch interessanter ist es, die Funktionen in einen Assoziativspeicher einzusetzen und dann über einen Namen zu erfragen. Diese Implementierung nutzt kein Feld, sondern eine Datenstruktur Map. Eine Erweiterung der Idee nutzt dann auch gleich Enums und EnumMap zur Assoziation zwischen Aufzählung und Funktion.


Galileo Computing - Zum Seitenanfang

7.1.4 Implementierung einer verketteten Liste topZur vorigen Überschrift

Verkettete Listen gibt es in Java seit Java 1.2 über die Klasse LinkedList, sodass wir die Implementierung eigentlich nicht betrachten müssten. Da es für viele Leser jedoch noch ein Geheimnis ist, wie die dazu benötigten Pointer in Java abgebildet werden, sehen wir uns eine einfache Implementierung an. Zunächst benötigen wir eine Zelle, die Daten und eine Referenz auf das folgende Listenelement speichert. Die Zelle wird durch die Klasse Cell modelliert. Im UML-Diagramm taucht die innere Klasse im letzten Block auf.

Listing 7.8 com/tutego/insel/list/LinkedList.java

package com.tutego.insel.list; 
 
public class LinkedList 
{ 
  private Cell head, tail; 
 
  static class Cell 
  { 
    Object data; 
    Cell   next; 
  } 
 
  public void add( Object o ) 
  { 
    Cell newCell = new Cell(); 
    newCell.data = o; 
 
    if ( head == null )                // or tail == null 
      head = tail = newCell; 
    else 
      tail = tail.next = newCell; 
  } 
 
  public void addAll( Object... os ) 
  { 
    for ( Object o : os ) 
      add( o ); 
  } 
 
  @Override 
  public String toString() 
  { 
    StringBuilder sb = new StringBuilder( 1024 ).append( '[' ); 
 
    for ( Cell cell = head; cell != null; ) 
    { 
      sb.append( cell.data ); 
 
      if ( cell.next != null ) 
        sb.append( ", " ); 
 
      cell = cell.next; 
    } 
 
    return sb.append( ']' ).toString(); 
  } 
}

Eine verkettete Liste besteht aus einer Menge von Cell-Elementen. Da diese Objekte fest mit der Liste verbunden sind, ist hier der Einsatz von geschachtelten Klassen sinnvoll. Cell ist hier statisch, kann aber auch Elementklasse sein, doch ist das egal, weil die Klasse von außen nicht sichtbar ist.

Die Liste benötigt zum Einfügen einen Verweis auf den Kopf (erstes Element) und auf das Ende (letztes Element). Um nun ein Element dieser Liste hinzuzufügen, erzeugen wir zunächst eine neue Zelle newCell. Ist tail oder head gleich null, bedeutet dies, dass es noch keine Elemente in der Liste gibt. Danach legen wir die Referenzen für Listenanfang und –ende auf das neue Objekt. Werden nun später Elemente eingefügt, hängen sie sich hinter tail. Wenn es schon Elemente in der Liste gibt, dann ist head oder tail nicht gleich null, und tail zeigt auf das letzte Element. Seine next-Referenz zeigt auf null und wird dann mit einem neuen Wert belegt, nämlich mit dem des neu beschafften Objekts newCell. Nun hängt es in der Liste, und das Ende muss noch angepasst werden. Daher legen wir die Referenz tail auch noch auf das neue Objekt.

Listing 7.9 com/tutego/insel/list/LinkedListDemo.java, main()

LinkedList l = new LinkedList(); 
l.addAll( "Hallo", "Otto" );


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück



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