© APSIS GmbH |
Seite 171
Abb. 8.1: Datenbehälter für Buchstaben, für Telefonbucheinträge und für Messwerte
Seite 172
Abb. 8.2: Mengenoperationen
Seite 172
import lehrbuch.Farbe; // (8.1) public interface Farbmenge { // alle final-Parameter sind auch const public void entleeren(); // löscht alle Farben aus der Farbmenge public void fuellen(final Farbe farbe); // trägt farbe die Farbmenge ein public void entfernen(final Farbe farbe); // löscht Farbe aus der Farbmenge public boolean vorhanden(final Farbe farbe); // const ¬ }
import lehrbuch.kapitel8.Farbmenge; // Schnittstelle // (8.2) import lehrbuch.kapitel8.FarbmengeImpl; // Implementierung import lehrbuch.Farbe; public class ImmerGruen { public static void main(String args[]) { Farbmenge menge = new FarbmengeImpl(); // ¬ menge.fuellen(Farbe.ROT); // ¬ menge.fuellen(Farbe.ROT); // keine Veränderung menge.fuellen(Farbe.GRUEN); menge.entfernen(Farbe.ROT); menge.entfernen(Farbe.ROT); // keine Veränderung ¬ boolean gruenIstDa = menge.vorhanden(Farbe.GRUEN); // true } }
menge.kopieren(andereMenge); // kopieren aus FarbmengeImpl
Übung 8.1: Erstellen Sie ein menügesteuertes Programm für zwei Farbmengen mit Vorwahl (s. Übung 6.8 auf Seite 133). Generieren Sie mit Hilfe des Menügenerators das Menü, in das die einzelnen Operationsaufrufe eingebunden werden: "Erste Menge", "Zweite Menge" (Vorwahl), "Fuellen" (Auswahl der Farbe), "Entfernen" (mit Auswahl einer Farbe), "Entleeren" und "Vorhanden" (Auswahl einer Farbe, Ergebnis über meldung).
Seite 173
public interface ErwFarbmenge extends Farbmenge { // (8.3) public void und(final ErwFarbmenge menge); // const menge; // Schnitt public void oder(final ErwFarbmenge menge); // const menge; // Vereinigung public void entweder(final ErwFarbmenge menge); // const menge; public void nicht(); // const menge; // Komplement public boolean leer(); // const public void kopieren(final ErwFarbmenge quelle) throws VollAusn; // const quelle public boolean gleich(final ErwFarbmenge menge); // const menge; const }
Abb. 8.3: Erweiterung und Implementierung
Übung 8.2: Ergänzen Sie Ihre Lösung der Übung 8.1 auf Seite 173 mit Menüpunkten, in denen Sie auch die Mengenoperationen testen. Benutzen Sie dabei die implementierende Klasse kapitel8.ErwFarbmengeImpl.
Seite 174
public interface Zeichenmenge { // (8.4) public void entleeren(); // löscht alle Zeichen aus Zeichenmenge public void fuellen(final lehrbuch.Char zeichen); // trägt zeichen ein public void entfernen(final lehrbuch.Char zeichen); // löscht zeichen public boolean vorhanden(final lehrbuch.Char zeichen); public void allesAnzeigen(); // const // zeigt die gespeicherten Zeichen an }
Übung 8.3: Erstellen Sie ein menügesteuertes Programm (wie in der Übung 8.1 auf Seite 173) für zwei Zeichenmengen mit Vorwahl.
Übung 8.4: Erweitern Sie die obige Schnittstelle Zeichenmenge um die mengentheoretischen Operationen Vereinigung, Schnitt und Komplement. Ergänzen Sie auch Ihr menügesteuertes Programm aus der Übung 8.3 durch Menüpunkte, mit deren Hilfe Sie die Vereinigung und den Schnitt Ihrer beiden Zeichenmengen sowie das Komplement von einer der beiden berechnen können. In die Implementierung müssen Sie zunächst einmal leere Methoden, d.h. Attrappen (dummies) einsetzen, da wir es noch nicht gelernt haben, wie Multibehälter implementiert werden.
Seite 175
public interface PersZeichenmenge extends Zeichenmenge { // (8.5) public void speichern(String dateiname) throws DateiAusn; // const ¬ // Datei wird überschrieben, Objekt bleibt unverändert public void laden (final String dateiname) throws DateiAusn; // ¬ // Objekt wird überschrieben, Datei bleibt unverändert }
Übung 8.5: Beweisen Sie mit Hilfe eines Stapeltestprogramms (also kein Dialogprogramm), dass die Klasse kapitel8.PersZeichenmengeImpl persistent ist: Versorgen Sie zuerst Ihre Menge mit Inhalt und speichern Sie sie; anschließend erzeugen Sie ein neues Mengenobjekt, laden Sie sie und überprüfen Sie seinen Inhalt.
Seite 175
public interface Menge { // (8.6) public void entleeren(); // löscht alle Elemente aus der Menge public void fuellen(final Object element); public void entfernen(final Object element); public boolean vorhanden(final Object element); // const public boolean leer(); // const public void und(final Menge menge); // Schnitt public void oder(final Menge menge); // Vereinigung // public void entweder(final Menge menge); // nur für diskrete Mengen implementierbar, s. Kapitel 8.1.7. // public void nein(); // Komplement nur für diskrete Mengen implementierbar // public boolean voll(); // const // nur für diskrete Mengen implementierbar // public void kopieren(final Menge quelle) throws VollAusn; /* die Vergleichs- und Persistenzmethoden nehmen wir nicht in die Schnittstelle auf, damit sie nicht in jeder Implementierung enthalten sein müssen; das Kommentar empfiehlt, sie auch zu implementieren */ // public boolean gleich(final Menge menge); // const // public void speichern(String dateiname) throws DateiAusn; // const // public void laden (final String dateiname) throws DateiAusn; }
public MengeGen(final Object reg); // Konstruktor mit Registrierungsobjekt public MengeGen(final MengeGen quelle); // Kopierkonstruktor
MengeGen farbmenge = new MengeGen(Farbe.GRUEN); // Registrierungsobjekt // (8.7) MengeGen eimermenge = new MengeGen(new Eimer()); // anonymes Registrierungsobjekt
Farbe farbe = Farbe.ROT; farbmenge.fuellen(farbe); farbmenge.fuellen(Farbe.GRUEN); // anonymes Objekt wird in die Menge eingetragen Eimer eimer = new Eimer(); eimer.fuellen(); eimermenge.fuellen(eimer);
farbmenge.fuellen(eimer); // throws GenFehler
Seite 177
class MengeGen implements Menge { // (8.8) public MengeGen(final Object element) { ... } // merkt Klasse von element public MengeGen(final MengeGen menge) { ... } // like menge public void fuellen(final Object element) { ... } // like element // überprüft, ob der Parameter element von der Klasse ist wie der vom Konstruktor ... // die Implementierung der weiteren Methoden aus Menge }
class MengePol implements Menge { // (8.9) public MengePol() { ... } public MengePol(final MengePol menge) { ... } public void fuellen(final Object element) { ... } // keine Überprüfung ... // die Implementierung der weiteren Methoden aus Menge }
Seite 178
public interface DiskreteMenge { // alle final-Parameter sind auch const // (8.10) public void fuellen(final Aufz element); // like element ... // usw. wie im Programm (8.6); zusätzlich noch das Komplement: public void nein(); // Komplement, für diskrete Mengen implementierbar }
public void fuellen(final Object element);
public void fuellen(final Aufz element);
class Geschlecht extends lehrbuch.Aufz { // (8.11) public static final Geschlecht MAENNLICH = new Geschlecht(); public static final Geschlecht WEIBLICH = new Geschlecht(); public static final Geschlecht SAECHLICH = new Geschlecht(); }
DiskreteMenge eimermenge = new DiskreteMengeGen(new lehrbuch.Eimer()); // Fehler // wird vom Compiler abgelehnt, da Eimer nicht Unterklasse von Aufz DiskreteMenge geschlechtmenge = new DiskreteMengeGen(Geschlecht.MAENNLICH);
geschlechtmenge.fuellen(Farbe.ROT); // throws GenFehler
Seite 179
public interface AnzeigbareMenge extends Menge { // (8.12) public void allesAnzeigen(); // const // zeigt die gespeicherten Elemente an }
public interface IterierbareMenge extends Menge { // (8.13) public void iterator(String rueckruf); // ruft rueckruf für jedes Element auf }
public class Tier extends lehrbuch.Aufz { // (8.14) public static final Tier ELEFANT = new Tier(); ... // alle Tiere ähnlich public void tierAnzeigen() { // zeigt ein Tierfoto am Bildschirm an ¬ System.out.println(text()); // primitive Version } }
import lehrbuch.kapitel8.IterierbareMengeImpl; public class Safari { public static void main(String args[]) { Tier geschossenesTier = Tier.ELEFANT; IterierbareMengeImpl menge = new IterierbareMengeImpl(geschossenesTier); geschossenesTier = (Tier)geschossenesTier.auswahl(); // oder geschossenesTier anders bestimmen menge.fuellen(geschossenesTier); ... // weitere Tiere eintragen menge.iterator("tierAnzeigen"); // ruft für jedes Tier tierAnzeigen auf } }
Übung 8.6: Prägen Sie die Klasse kapitel8.MengeGen für Zeichen (d.h. für die Klasse lehrbuch.Char) aus. Benutzen Sie die Ausprägung an Stelle von ZeichenmengeImpl in Ihrem menügesteuerten Programm aus der Übung 8.3 auf Seite 175.
Seite 180
public interface Zeichensack { // alle final-Parameter sind auch const // (8.15) public void entleeren(); // löscht alle Zeichen aus dem Zeichensack public void fuellen(final lehrbuch.Char zeichen); public void entfernen(final lehrbuch.Char zeichen) throws KeinEintragAusn; public void alleEntfernen(final lehrbuch.Char zeichen); public boolean vorhanden(final lehrbuch.Char zeichen); public boolean leer(); // const public void allesAnzeigen(); // zeigt jedes eingetragene Zeichen des Sackes an // public void kopieren(final Zeichensack quelle) throws VollAusn; // public boolean gleich(final Zeichensack sack); // const // public void speichern(String dateiname) throws DateiAusn; // const // public void laden (final String dateiname) throws DateiAusn; // public void iterator(String rueckruf); }
Übung 8.7: Verwenden Sie die Klasse kapitel8.ZeichensackImpl (sie implementiert Zeichensack) in Ihrem Programm aus der Übung 8.3 auf Seite 175 an Stelle von kapitel8. ZeichenmengeImpl. Wenn ein Zeichen mehrfach mit fuellen (durch eine geeignete Menüauswahl) eingetragen und eins davon mit entfernen gelöscht wird, meldet vorhanden immer noch true. Der Aufruf der Operation allesAnzeigen beweist auch, dass mehrfach eingetragene Zeichen mehrfach vorhanden sind.
Übung 8.8: Fertigen Sie die allgemeine Version Sack der obigen Schnittstelle an und erweitern Sie sie zur Schnittstelle SackAlgebra, indem Sie Operationen hinzufügen, mit denen die Summe und die Differenz zweier Säcke errechnet werden kann. Prägen Sie eine Implementierung (mit Attrappen, d.h. leeren Methoden) Ihrer Erweiterung für Farben in einem Testprogramm aus.
Seite 181
Seite 181
public interface Zeichenfolge { // (8.16) public void entleeren(); // löscht den gesamten Inhalt public void fuellen(final char zeichen); // trägt element ein public void entfernen(int index) throws LeerAusn; // löscht mit Index ¬ public char lesen(int n) throws LeerAusn; // liefert das Zeichen mit Index ¬ public boolean leer(); // const ... Iterator, Persistenzoperationen, Kopieren und Gleichheit als Kommentar
Übung 8.9: Entwickeln Sie die allgemeine Schnittstelle Folge mit allen üblichen Multibehälter-Operationen. Nehmen Sie dazu auch die Operation zusammenfuegen (oder konkatenieren) und evtl. noch einige von Ihnen ausgedachte (z.B. invertieren, d.h. die Reihenfolge der Elemente umkehren) dazu.
Seite 182
Abb. 8.4: Folgen mit eingeschränktem Zugriff
Seite 182
public interface Warteschlange { // alle final-Parameter sind auch const // (8.17) public void entleeren(); // ensures leer() public void eintragen(Object element) throws VollAusn; // like element // requires !voll(); ensures !leer() public Object lesen() throws LeerAusn; // requires !leer() public void entfernen() throws LeerAusn; // like element // requires !leer(); ensures !voll() public boolean leer(); // const public boolean voll(); // const // public void kopieren(final Warteschlange quelle) throws VollAusn; // like quelle; // ensures gleich(quelle) // public boolean gleich(final Warteschlange warteschlange); // const // like warteschlange // public void speichern(String dateiname) throws DateiAusn; // const // public void laden(final String dateiname) throws DateiAusn; // diesmal kein iterator, da nur der älteste Eintrag sichtbar ¬ }
farbenschlange.eintragen(Farbe.ROT); // aufwärtskompatibel
Farbe farbe = (Farbe)farbenschlange.lesen();
Übung 8.10: Prägen Sie eine generische Implementierung dieser Schnittstelle (z.B. die Klasse lehrbuch.kapitel8.WarteschlangeListe), für eine Aufzählungsklasse Ihrer Wahl (wie z.B. lehrbuch.Farbe) aus, und rufen Sie ihre Operationen menügesteuert auf. Fangen Sie dabei die exportierten Ausnahmen auf, indem Sie den Anwender über ein Meldungsfenster über die fehlgeschlagene Aktion informieren.
Seite 184
class Patient extends lehrbuch.Aufz { // (8.18) public static final Patient MAYER = new Patient(); public static final Patient MUELLER = new Patient(); ... // alle Patienten werden aufgelistet }
public class Arztpraxis extends MenueArzt { // generiert mit zwei Menüpunkten private lehrbuch.kapitel8.Warteschlange liste = new lehrbuch.kapitel8.WarteschlangeGen(Patient.MAYER, 20); protected void patientKommt() { // Rückrufprozedur für den ersten Menüpunkt try { lehrbuch.Aufz patient = Patient.MAYER; patient = patient.eingabe(); // throws BereichAusn; // keine Typkonvertierung nötig, weil patient vom Typ Aufz vereinbart wurde liste.eintragen(patient); // throws VollAusn; // ¬ } catch(lehrbuch.BereichAusn ausnahme) { lehrbuch.Programm.meldung("Patient unbekannt", "Tippfehler"); } catch(lehrbuch.kapitel8.VollAusn ausnahme) { lehrbuch.Programm.meldung("Draußen warten", "Wartezimmer voll"); } } protected void dieNaechsteBitte() { // Rückruf für den zweiten Menüpunkt try { lehrbuch.Aufz patient = liste.lesen(); // throws LeerAusn; // keine Typkonvertierung nötig, weil patient vom Typ Aufz vereinbart wurde patient.meldung("Patient ausrufen"); liste.entfernen(); // Patient wird aus der Liste ausgetragen ¬ } catch(lehrbuch.kapitel8.LeerAusn ausnahme) { lehrbuch.Programm.meldung("Feierabend"); // kein Patient wartet } } } // menue wird nun mit patientKommt und dieNaechsteBitte von start aufgerufen
Übung 8.11: Entwerfen und implementieren Sie auf diese Weise das menügesteuerte Programm Nikolaus, das wartenden Kindern (aus einem Objekt der Klasse kapitel8.WarteschlangeGen) Geschenke aus seinem Sack (kapitel8.SackGen) verteilt. Die Namen der Kinder und die Geschenke listen Sie im Programm als Werte einer Aufzählungsklasse auf. Der Anwender des Programms soll wählen, wann der Nikolaus ein Geschenk einkauft (und es in sein Sack legt), wann ein Kind bei ihm ankommt (und sich in die Warteschlange einreiht) und wann er das am längsten wartende Kind beschenkt. Das Geschenk soll über eine Auswahlliste ausgesucht werden; wenn der Nikolaus es nicht (mehr) in seinem Sack hat, muss er es über eine geeignete Meldung ablehnen.
Seite 185
public interface Stapel { // (8.19) public void entleeren(); // ensures leer(); public void eintragen(Object element) throws VollAusn; // requires !voll(); ensures !leer() & lesen() == element public Object lesen() throws LeerAusn; // requires !leer() public void entfernen() throws LeerAusn; // requires !leer(); ensures !voll(); public boolean leer(); // const public boolean voll(); // const // public void kopieren(final Stapel quelle) throws VollAusn; // like quelle // ensures gleich(quelle); // public boolean gleich(final Stapel stapel); // like stapel const // public void speichern(String dateiname) throws DateiAusn; // const // public void laden(final String dateiname) throws DateiAusn; // public void allesEntleeren(String rueckruf); // Anstelle des Iterators // ruft rueckruf für alle Elemente auf und löscht diese }
StapelGen eimerStapel = new StapelGen(new Eimer());
package java.util; // (8.20) public class Stack extends Vector { // s. Kapitel 9.3.9. public Stack(); public void push(Object item); // entspricht eintragen public Object pop(); // ¬ public Object peek(); // entspricht lesen ¬ public boolean empty(); // entspricht leer public int search(Object object); // ¬ }
Übung 8.12: Gestalten Sie Ihr Programm aus der Übung 8.10 auf Seite 184 (FIFO-Farbbehälter) in einen LIFO-Farbbehälter um, indem Sie die generische Klasse kapitel8.StapelGen mit Farbe ausprägen. Zeigen Sie den Unterschied zwischen einer Warteschlange und einem Stapel.
Seite 187
public interface PosListe { // alle final-Parameter sind auch const // (8.21) public void entleeren (); // ensures leer(); public void eintragen (Object element) throws VollAusn; // requires !voll(); ensures !leer() & aktuellesElement()==element; // trägt Element nach dem Element an der aktuellen Position in die Liste ein public void erstesEintragen(final Object element) throws VollAusn; // requires !voll(); ensures !leer() & aktuellesElement()==element; // trägt Element an die erste Position in die Liste ein public Object aktuellesElement() throws LeerAusn; // requires !leer(); // liefert das Element an der aktuellen Position der Liste public void loeschen() throws LeerAusn; // requires !leer(); // löscht das aktuelle Element aus Liste public void anfang() throws LeerAusn; // positioniert auf das erste Element public void ende() throws LeerAusn; // positioniert auf das letzte Element der Liste public void vorwaerts() throws LeerAusn; // navigiert eine Position nach vorne public void rueckwaerts() throws LeerAusn; // navigiert eine Position zurück public void suchen(final Object element) throws NichtGefundenAusn; // ensures aktuellesElement == element; // positioniert auf das nächste Vorkommnis von element nach der aktuellen // ... Iterator, Persistenzoperationen, Kopieren und Gleichheit als Kommentar }
Übung 8.13: Rufen Sie die Operationen der generischen positionierbaren Liste kapitel8.PosListeGen für Farben menügesteuert auf. Testen Sie die Wirkung der Navigationsoperationen.
Seite 187
public class MengePol implements Menge { // Schnittstelle aus (8.6) // (8.22) private PosListePol liste; public MengePol() { // Konstruktor liste = new PosListePol(); // ¬ } public MengePol(final MengePol quelle) { liste = new PosListePol(quelle.liste); // Kopierkonstruktor weitergereicht } public void entleeren() { liste.entleeren(); } // weitergereicht public void fuellen(final Object element) { // ¬ try { liste.anfang(); liste.suchen(element); // gefunden, keine Veränderung } catch (PosListePol.NichtGefundenAusn ausnahme) { // eintragen: ¬ try { liste.eintragen(element); // throws VollAusn } catch (VollAusn voll) { System.err.println("Programmfehler"); } /* kommt hoffentlich nicht vor: Die Schnittstelle Menge sieht den Fall nicht vor, dass beim Eintragen die Menge voll wird; er ist sehr unwahrscheinlich, dass der Speicher erschöpft ist, zumal jedes Element nur einmal aufgenommen wird */ } } public void entfernen(final Object element) { ... // ähnlich: wenn gefunden, loeschen; ansonsten keine Veränderung public boolean vorhanden(final Object element) { ... // ähnlich: wenn gefunden, true; ansonsten false public void iterator(String rueckruf) { // ruft rueckruf für alle Elemente auf liste.iterator(rueckruf); } ... leer, kopieren, gleich, speichern und laden ähnlich einfach weiterreichen }
Übung 8.14: Implementieren Sie Stapel polymorph mit Hilfe der Klasse PosListePol.
Seite 188
W1 | W2 | ... | Wi | Wi+1 | ... | Wn | Datei |
| ® | Position | |||||
| Lesen | ||||||
| Zurücksetzen |
Abb. 8.5: Sequenzielle Datei
public interface SeqDatei { // alle final-Parameter sind auch const // (8.23) public void neuBeschreiben(); // macht die Datei leer, bereit zum Beschreiben public void zuruecksetzen(); // macht die Datei bereit zum Lesen public void eintragen(final Object element) throws LesemodusFehler; /* trägt element an das Ende der Datei ein; nur im Schreibmodus; Ausnahme LesemodusFehler, wenn neuBeschreiben gar nicht oder nicht nach zuruecksetzen aufgerufen wurde */ public void naechstesElement() throws SchreibmodusFehler, DateiendeAusn; /* schreitet zum nächsten Element; SchreibmodusFehler, wenn zuruecksetzen gar ¬ nicht oder nicht nach neuBeschreiben aufgerufen wurde; DateiendeAusn, falls naechstesElement öfter als eintragen aufgerufen wurde */ public Object aktuellesElement() throws SchreibmodusFehler, DateiendeAusn; // const // liefert das Element an der aktuellen Position public boolean endeDerDatei() throws SchreibmodusFehler; // true wenn der Aufruf naechstesElement die DateiendeAusn auslösen würde // public void kopieren(final SeqDatei quelle) throws VollAusn; // public boolean gleich(final SeqDatei quelle); // diesmal kein Iterator, keine Persistenzoperationen // exportierte Ausnahmen: public class LesemodusFehler extends Error {} public class SchreibmodusFehler extends Error {} public class DateiendeAusn extends Exception {} }
Übung 8.15: Implementieren Sie die Schnittstelle SeqDatei mit Hilfe der generischen Klasse PosListeGen.
Seite 190
Abb. 8.6: Sortierkanal
public interface Geordnet { // (8.24) public boolean kleiner(Geordnet objekt); // vergleicht zwei Objekte // a.kleiner(b) && b.kleiner(c) impliziert a.kleiner(c) }
public interface Sortierkanal { // (8.25) public void entleeren (); public void eintragen (final Geordnet element) throws VollAusn; public void entfernen() throws LeerAusn; // des kleinsten Elements public Geordnet kleinstesLesen() throws LeerAusn; public boolean voll(); // weiteres Eintragen nicht möglich public boolean leer(); // Iterator, Persistenzoperationen, Kopieren und Gleichheit wie üblich als Kommentar }
class GeordneteFarbe extends Aufz implements Geordnet { // (8.26) public static final GeordneteFarbe ROT = new GeordneteFarbe(); ... // Aufzählungswerte und Konstruktore wie üblich public boolean kleiner(Geordnet farbe) { // ¬ return kleiner(farbe); } }
... SortierkanalGen farbkanal = new SortierkanalGen(GeordneteFarbe.ROT); GeordneteFarbe farbe = GeordneteFarbe.ROT; farbkanal.eintragen(farbe); ... // weitere Farben eintragen GeordneteFarbe kleinstes = (GeordneteFarbe)farbkanal.kleinstesLesen();
class GeordneterEimer extends Eimer implements Geordnet { public boolean kleiner(Geordnet eimer) { boolean ergebnis; ... // Algorithmus, der bestimmt, wie zwei Eimer miteinander verglichen werden // (z.B. nach Inhalt oder Position) return ergebnis; } }
GeordneterEimer eimer = new GeordneterEimer(); SortierkanalGen eimerKanal = new SortierkanalGen(eimer);
eimer.fuellen(); eimerKanal.eintragen(eimer);
eimer = (GeordneterEimer)eimerKanal.kleinstesLesen(); eimer.anzeigen();
Seite 192
Abb. 8.7: Assoziativspeicher
Seite 192
public interface AssoSpeicher { // (8.27) public void entleeren(); public void eintragen(final Object schluessel, final Object element) // ¬ throws VollAusn; public Object finden(final Object schluessel) throws NichtVorhandenAusn; // const ¬ public boolean vorhanden(final Object schluessel); // const public boolean leer(); // const public boolean voll(); // const public class NichtVorhandenAusn extends Exception {} // Iterator, Persistenzoperationen, Kopieren und Gleichheit wie üblich als Kommentar }
AssoSpeicherGen telefonbuch = new AssoSpeicherGen(telefonnummer, teilnehmer);
public interface AssoTab extends AssoSpeicher { // (8.28) public Object naechstesFinden() throws NichtVorhandenAusn; }
Übung 8.16: Schreiben Sie einen Stapeltesttreiber für den Assoziativspeicher. Im Gegensatz zu einem Dialogtesttreiber ist dies ein konstantes Programm: Es läuft jedes Mal gleich ab. Sein Sinn ist, dass es für verschiedene Implementierungen der zu testenden Klasse (z.B. nach einer Fehlerkorrektur) ihre jeweilige Funktionalität überprüfen kann. Die Testdaten werden hier nicht interaktiv eingegeben, sondern sind im Programm festgelegt.
Prägen Sie nun den Assoziativspeicher mit den Klassen lehrbuch.Char und Buchstabe aus, wobei diese letztere eine Aufzählungsklasse mit den Buchstaben von A bis Z sein soll. Sie bildet den Schlüssel: Jedem seiner Werte wird der entsprechende Buchstabe der Klasse lehrbuch.Char zugeordnet. Ihr Programm soll 20 Eintragungen (in gemischter Reihenfolge) in den Assoziativspeicher vornehmen. Überprüfen Sie anschließend mit Ausgabe über System.out.println, ob alle 20 ordnungsgemäß eingetragen werden.
Seite 193
public interface DirDatei { // alle final-Parameter sind auch const // (8.29) public void neuBeschreiben(); // macht die Datei leer, bereit zum Beschreiben public void zuruecksetzen(); // macht die Datei bereit zum Lesen public void eintragen(final Object element) throws LesemodusFehler; /* trägt element an das Ende der Datei ein; nur im Schreibmodus; schluessel kann abgefragt werden; Ausnahme LesemodusFehler, wenn neuBeschreiben gar nicht oder nicht nach zuruecksetzen aufgerufen wurde */ public int schluessel(); // gibt den Schlüssel der aktuellen Position zurück public void positionieren(int schluessel) throws DateiendeAusn, SchreibmodusFehler; // ¬ public void naechstesElement() throws SchreibmodusFehler, DateiendeAusn; /* schreitet zum nächsten Element; SchreibmodusFehler, wenn zuruecksetzen gar nicht oder nicht nach neuBeschreiben aufgerufen wurde; DateiendeAusn, falls naechstesElement öfter als eintragen aufgerufen wurde */ public Object aktuellesElement() throws SchreibmodusFehler, DateiendeAusn; // const // liefert das Element an der aktuellen Position; nur im Lesemodus public boolean endeDerDatei() throws SchreibmodusFehler; // true wenn naechstesElement die DateiendeAusn auslöst; nur im Lesemodus // public void kopieren(final SeqDatei quelle) throws VollAusn; // public boolean gleich(final SeqDatei quelle); // diesmal kein Iterator, keine Persistenzoperationen public class LesemodusFehler extends Exception {} public class SchreibmodusFehler extends Exception {} public class DateiendeAusn extends Exception {} }
© APSIS GmbH |