www.r-krell.de |
Webangebot für Schule und Unterricht, Software, Fotovoltaik und mehr |
Willkommen/Übersicht > Informatik > Informatik-Seite d)
Teil d): Fuhrpark-Verwaltung
Die Überschriften a) bis c) verweisen auf vorhergehenden Seiten, die Überschriften d) bis h) auf nachfolgende Seiten.
a) Grundlegendes zu Java, benötigte Software (inkl. Downloadadressen) und
Installation
b) Erste Java-Programme (u.a. Autorennen u. Aufzug) sowie Verweise (Links) auf fremde
Java-Seiten
c) Sortieren und Suchen in Java sowie grafische Oberflächen mit der
Java-AWT
d) Adressbuch- und Fuhrpark-Verwaltung sowie Datei-Operationen mit Java:
e) Lineare Abstrakte Datentypen (Keller, Schlangen, Listen) und einige Anwendungen
(z.B. Tiefen- und Breitensuche im Labyrinth)
f) Abstrakter Datentyp Baum ([binärer] Sortierbaum, Rechenbaum, Spielbaum)
g) Abstrakter Datentyp Graph (Adjazenzmatrix u. -listen, typische Fragestellungen, Tiefen- u.
Breitensuche)
h) Bau eines Compilers Java -> 1_AMOR (Syntaxdiagramm, Scanner, Parser, Variablentabelle,
Codeerzeuger)
Eine vollständige Übersicht aller Java-Seiten gibt's auf der Informatik-Hauptseite!
zum Seitenanfang / zum Seitenende
Vorwort
Das auf meiner Java-Seite c) Gelernte (nämlich der Umgang mit Reihungen einschließlich dem Suchen und Sortieren) wird jetzt auf ein anspruchsvolleres Projekt übertragen. Nicht mehr nur Reihungen einfacher Zahlen werden betrachtet, sondern es soll ein Adressbuch aufgebaut werden, in das man die Namen, Geburtstage, Anschriften und Telefonnummern von Bekannten und Freunden eintragen kann. Das Adressbuch muss natürlich nicht nur die Datensätze aufnehmen, sondern auch verwalten können: Gezieltes Suchen, Löschen u.ä. ist/sind gefordert.
Während die Schülerinnen und Schüler in meinem Unterricht an dem Adressbuch gearbeitet haben, habe ich gemerkt, dass z.T. sehr komfortabel zu bedienende, optisch anspruchsvolle Programme entstanden, die Programmierung dahinter oft aber nicht modernen Grundsätzen der Verwendung möglichst in sich abgeschlossener, wiederverwendbarer Module gehorchte. Andere Schülerinnen und Schüler taten sich mit dem Transfer des bei Zahlenreihen Gelernten schwer, so dass ich parallel zum nach wie vor recht selbstständig zu bearbeitenden Schülerprojekt „Adressbuch" die Verwaltung eines kleinen Fuhrparks im Unterricht erarbeitet und besprochen habe. Mit dem Fuhrpark-Musterprojekt sollten allgemeine Grundlagen vermittelt und Anregungen für die Übernahme entsprechender Techniken auf das Adressbuch-Projekt gegeben werden.
Da es natürlich wenig Spaß macht, bei jedem Programmstart alle Einträge neu über die Tastatur einzugeben, sollte auch auf die Festplatte oder eine Diskette abgespeichert werden bzw. von dort geladen werden können. Das erforderte einen Einschub über die Datei-Behandlung in Java. Dieser sowie verschiedene Entwicklungsstadien des Fuhrpark-Projekts sind im Folgenden durch einige Arbeitsblätter bzw. Beispielprogramme dokumentiert; später sollen Schülerprojekte folgen (wobei ein Schüler das Adressbuch direkt als Datenbank-Applikation geschrieben hat, und statt mit den 'normalen', nachstehend beschriebenen Dateioperationen per SQL-Befehlen aus Java auf eine entsprechende Datenbank zugreift).
Angemerkt werden muss noch, dass die Sicherheitsrichtlinien von Java nur Applikationen den Zugriff auf Diskette oder Festplatte erlauben, nicht aber Applets.
zum Seitenanfang / zum Seitenende
Vernünftige Klasseneinteilung für die Fuhrpark-Verwaltung
Ein Fuhrpark besteht aus Autos. Die Verwaltung des Fuhrparks soll über eine grafische Benutzeroberfläche erfolgen. Entsprechend liegt es nahe, eigene Klassen für ein Auto, den ganzen Fuhrpark und die Benutzeroberfläche (GUI = graphical user interface) einzurichten. Während die Eigenschaften bzw. Datenfelder und benutzte Objekte den Klassen recht leicht zugeordnet werden können (ein Auto hat ein Kennzeichen, einen Hersteller, einen bestimmten km-Stand usw. - diese Daten gehören also in die Autoklasse; die Reihung zur Aufnahme mehrerer Autos gehört in die Fuhrpark-Klasse während Textfelder und Bildschirmknöpfe sicher Objekte sind, die in die GUI-Klasse gehören), war bei den Methoden schon mehr Nachdenken nötig. Ein Vorgang wie z.B. das Aufnehmen eines neuen Autos in den Fuhrpark, erfordert Aktionen in mehreren bzw. allen Klassen. In der Oberfläche befinden sich die Eingabefelder: hier wird auf den auslösenden Knopfdruck reagiert. Dann werden die gesammelten und eventuell noch konvertierten Daten an das Fuhrpark-Klasse bzw. das zur Laufzeit eingerichtete Fuhrpark-Objekt gemäß der Beschreibung der Fuhrpark-Klasse weiter gereicht (Klassen sind die Baupläne der Objekte). Im Fuhrpark wird ein passender Platz in der Reihung ausgesucht und die Anzahl der Autos erhöht. Die individuellen Auto-Daten müssen aber letztlich beim Auto eingetragen werden, also die Datenfelder eines Kfz-Objekts ändern, weswegen eine passende Methode der Kfz-Klasse aufgerufen werden muss. Zum Aufnehmen gibt es demnach Methoden in allen drei Klassen, die sich untereinander aufrufen. Um hier einem klaren Programmierstil zu erzwingen, sollten in jeden Fall explizite Methoden verwendet werden müssen und nicht einfach Datenfelder anderer Objekte/Klassen manipuliert werden können: Deshalb wurden die Datenfelder der Kfz- und Fuhrpark-Klasse als „private" deklariert und so fremdem Zugriff entzogen.
Grundsätzlich ist das ordentliche Aufteilen in Klassen schon früher geübt: so z.B. beim Sortieren (eine Klasse, die Zahlen verwaltet und die Arbeit macht, und die Oberflächenklasse mit der Benutzerschnittstelle - siehe meine Java-Seite c). Seit den ersten Java_Programmen wurde immer wieder auf eine ordentliche Klassen-Einteilung hingewiesen, so schon anfangs bei der „Grundsätzlichen Struktur von Java-Programmen" (besondere Startdatei) und in meinem Einführungstext (beides Java-Seite a)), bei Hochhaus, Autorennen und Aufzug - vgl. meine Java-Seite b) ! Trotzdem ist es offenbar leider nicht immer leicht und selbstverständlich, dass bei jedem neuen Projekt die eigentlich altbekannten Grundsätze auch beachtet und tatsächlich eingehalten werden.
Ein Arbeitsblatt mit dem Programmtext zu einer ersten Version der Fuhrpark-Verwaltung (passend zum oben gezeigten Bildschirmabdruck: noch ohne Dateien, aber mit einigen weiterführenden Aufgaben) kann hier als pdf-Datei angesehen bzw. mit rechtem Mausklick und „Ziel speichern unter.." herunter geladen und später in aller Ruhe gelesen werden:
Fuhrpark-Verwaltung, 1. Version:
java-kfzverw.pdf (58 kB)
Hier sind noch keine Methoden für's Suchen oder Sortieren angedeutet. Sonst müsste auch bereits beim einzelnen Kraftfahrzeug eine Vergleichsmethode implementiert werden.
zum Seitenanfang / zum Seitenende
Dateien in Java
Dateioperationen in Java werden über FileReader bzw. FileWriter vorgenommen, auf die BufferedReader/-Writer oder ObjectInput- bzw. -OutputStreams aufbauen. Im Unterricht wurden konkrete Beispiele genannt und programmiert; hier soll zunächst ohne weiteren Kommentar eine als pdf-Datei abrufbare Übersicht gegeben werden.
Typische Konstrukte für das Schreiben und Lesen von Dateien in Java:
java-dateiop.pdf (13 kB)
Im Unterricht 2003 habe ich übrigens auf die Dateien für einzelne Buchstaben und Zahlen (Typ 1, oberes Seitendrittel im Bild) ganz verzichtet und nur Dateien für Objekte eingeführt. Das reicht völlig und vermeidet Verwirrung. Ganz auf den Dateizugriff aus Java zu verzichten, um statt dessen nur eine Datenbank-Anbindung zu verwenden und dort die Informationen zu speichern und zu ordnen - dazu konnte ich mich noch nicht durchringen. Vermutlich ist der hier beschrittene Weg doch einfacher nach zu vollziehen und legt Grundlagen, die später für eine vernünftige Arbeit mit Datenbanken hilfreich sind.
zum Seitenanfang / zum Seitenende
Erweiterte Fuhrpark-Verwaltung
Anschließend gibt es eine kritische Anmerkung mit dem Vorschlag zu einem besseren Vorgehen als dem hier gezeigten.
Erweiterte Fuhrparkverwaltung (zum Herunterladen bzw. Ansehen im pdf_Format; trotzdem bitte unten den Verbesserungsvorschlag ansehen!):
java-kfzverw-dat.pdf (104 kB)
Erweiterte Fuhrparkverwaltung (Text nachfolgend abgedruckt):
Der Quelltext besteht aus vier Dateien, nämlich
zum Seitenanfang / zum Seitenende
//Kfz-Verwaltung, Datei 1/4
//Java JDK 1.1.18 -- Krell 21.2.2002/5.3.2002
import java.io.*; //für Serializable
public class Kfz implements Serializable //implements S.. für Datei-op.!
{
//Hier stehen die Daten, die ein (jedes) Auto beschreiben.
//Das vorangestellte private sorgt dafür, dass nur die Methoden
//dieser Klasse auf die Daten zugreifen dürfen (verhindert Fehler)
private String kennzeichen; // z.B. "D-AB 123"
private String hersteller; // z.B. "VW"
private String typ; // z.B. "Polo"
private int baujahr; // z.B. 1998
private int kmStand; // z.B. 42389
//Und hier kommen die Methoden, um die Daten zu ändern oder anzusehen:
public void merken (String nummer, String firma, String modell,
int jahr, int fahrtstrecke)
//Beim Aufruf auto.merken ("D-CD 234","Opel","Astra",2001,10893)
//werden die übergebenen Daten in die fünf Variablen eingetragen:
{
kennzeichen = nummer;
hersteller = firma;
typ = modell;
baujahr = jahr;
kmStand = fahrtstrecke;
}
public String nennen ()
//Gibt eine Zeichenkette mit allen Daten des Autos aus
{
String daten = "Das Auto mit der Nr. '"+kennzeichen+"', ein "+
hersteller+" "+typ+" von "+baujahr+", ist bisher "+kmStand+
" km gelaufen.";
return (daten);
}
public String nummer()
//Nennt nur das amtl. Kennzeichen des Autos, sonst nichts
{
return (kennzeichen);
}
public String hersteller()
//Nennt nur den Hersteller des Autos, sonst nichts
{
return (hersteller);
}
public int kmZahl ()
//Nennt nur den kmStand des Autos, sonst nichts
{
return (kmStand);
}
public void neuerStand (int km)
//Ändert nur den kmStand des Autos, sonst nichts
{
kmStand = km;
}
public void kopiereVon (Kfz anderesAuto)
//Kopiert alle Daten vom anderen Auto in eigene Daten
{
kennzeichen = anderesAuto.kennzeichen;
hersteller = anderesAuto.hersteller;
typ = anderesAuto.typ;
baujahr = anderesAuto.baujahr;
kmStand = anderesAuto.kmStand;
}
}
zum Seitenanfang / zum Seitenende
//Kfz-Verwaltung, Datei 2/4
//Java JDK 1.1.18 -- Krell 21.2.2002/5.3.2002
import java.io.*;
//Erzeugt und verwaltet Reihung fuhrpark aus 25 Objekten der Klasse Kfz
public class KfzFuhrpark
{
//Daten des Fuhrparks
private Kfz[] fuhrpark = new Kfz[25]; //(bis zu) 25 Autos im Fuhrpark
private int anzahlDerAutos = 0; //zunächst ist noch kein Auto bekannt.
//Erlaubt ist/sind 0 <= anzahlDerAutos <= 25
//Methoden zur Verwaltung des Fuhrparks
public KfzFuhrpark() //Automatische Initialisierung
{
for (int i=0; i<25; i++)
{
fuhrpark[i] = new Kfz(); //Erzeugen der 25 Objekte vom Typ Kfz
}
}
public int wagenAnzahl () //Sagt, wie viele Autos es gibt
{
return (anzahlDerAutos);
}
public void neuesAuto (String nummer, String produzent, String modell,
int jahr, int kmStand) //Erweitert fuhrpark um das angegebene Auto
{
fuhrpark[anzahlDerAutos].merken (nummer,produzent,modell,jahr,kmStand);
//Speichert Daten im fuhrpark an der indizierten Stelle durch Aufruf
//der Kfz-Methode merken. Jede der 25 fuhrpark-Komponenten ist ein Kfz!
anzahlDerAutos = anzahlDerAutos + 1;
//Durch die Neuaufnahme hat sich die Zahl der Autos um 1 erhöht!
}
public String ändereKmStand (String amtlKennzeichen, int neueKm)
//Ändert den kmStand des Autos mit dem angeg. Kennzeichen
{
String meldung = "Auto "+amtlKennzeichen
+" nicht gefunden -- km-Zahl nicht geändert";
//Finden des Index i vom Auto mit der gesuchten Nummer
int i = anzahlDerAutos - 1; //von hinten beginnen
while ((i>=0)&&(! fuhrpark[i].nummer().equals(amtlKennzeichen)))
{ //equals statt == , da versch. Objekte mit gleichem Inhalt
i = i-1;
}
//KmStand ändern
if (i>=0) //Auto gefunden -- sonst ist i = -1
{
fuhrpark[i].neuerStand (neueKm); //Aufruf der Kfz-Methode
meldung = "km-Zahl des Autos "+amtlKennzeichen+
" auf "+neueKm+" verändert";
}
return (meldung);
}
public String löschen (String altesKennzeichen)
//Löscht Auto mit dem angegebenen Kennzeichen aus dem Fuhrpark
{
String meldung = "Auto "+altesKennzeichen
+" nicht gefunden -- nicht gelöscht";
//Finden des Index i vom Auto mit der gesuchten Nummer
int i = anzahlDerAutos - 1; //von hinten beginnen
while ((i>=0)&&(! fuhrpark[i].nummer().equals(altesKennzeichen)))
{ //equals statt == , da versch. Objekte mit gleichem Inhalt
i = i-1;
}
//Auto löschen durch Vorziehen des Fuhrpark-Restes
if (i>=0) //Auto gefunden -- sonst ist i = -1
{
anzahlDerAutos--; //Löschen verkleinert Anzahl
for (int j=i; j < anzahlDerAutos; j++)
{
fuhrpark[j].kopiereVon (fuhrpark[j+1]); //nutzt Kfz-Methode
}
meldung = "Auto "+altesKennzeichen+" wurde gelöscht!";
}
return (meldung);
}
public String listeAutosVon (String produzent)
//Erzeugt Text mit den Daten der Autos vom genannten Hersteller
{
String ausgabe = "";
for (int i=0; i<anzahlDerAutos; i++)
{
if (fuhrpark[i].hersteller().equals (produzent))
{
ausgabe = ausgabe+(i+1)+".) "+fuhrpark[i].nennen()+"\n";
}
} //nutzt Kfz-Methode
return (ausgabe);
}
private void tausche (int i, int j)
// vertauscht innerhalb des Fuhrparks die beiden Autos
// an den Positionen i und j. Wird beim Sortieren benötigt.
{
Kfz drittesAuto = new Kfz(); //Zwischenspeicher
drittesAuto.kopiereVon (fuhrpark[i]);
fuhrpark[i].kopiereVon (fuhrpark[j]);
fuhrpark[j].kopiereVon (drittesAuto);
}
public void minSortNr () // MinSort nach Autonummer
// Sortieren durch Auswahl des jeweils kleinsten Elements im Rest
// und Tausch dieses Elements nach vorne. Nach dem 0. Durchgang steht
// also das kleinste Element ganz links auf Platz 0, beim nächsten Durchgang
// kommt das nächtkleinere Element auf Platz 1 usw., so dass die Sortierung
// von links nach rechts wächst
{
int minStelle, durchgang, stelle;
for (durchgang=0; durchgang<anzahlDerAutos; durchgang++)
{
minStelle = durchgang; // vorderstes El. im unsortierten Teil zum Vergleich
for (stelle=durchgang+1; stelle<anzahlDerAutos; stelle++)
{
if (fuhrpark[stelle].nummer().compareTo(fuhrpark[minStelle].nummer())<0)
{
// wird ein kleineres Element gefunden, so wird dessen Index gemerkt
minStelle = stelle;
}
}
// das gefundene kleinste Element wird nach vorne (auf den Platz mit
// dem Index durchgang) getauscht, sofern es nicht schon dort steht:
if (minStelle > durchgang)
{
tausche (durchgang, minStelle);
}
}
}
public void minSortKm () // MinSort nach km-Stand
// Sortieren durch Auswahl des jeweils kleinsten Elements im Rest
// und Tausch dieses Elements nach vorne. Nach dem 0. Durchgang steht
// also das kleinste Element ganz links auf Platz 0, beim nächsten Durchgang
// kommt das nächtkleinere Element auf Platz 1 usw., so dass die Sortierung
// von links nach rechts wächst
{
int minStelle, durchgang, stelle;
for (durchgang=0; durchgang<anzahlDerAutos; durchgang++)
{
minStelle = durchgang; // vorderstes El. im unsortierten Teil zum Vergleich
for (stelle=durchgang+1; stelle<anzahlDerAutos; stelle++)
{
if (fuhrpark[stelle].kmZahl() < fuhrpark[minStelle].kmZahl())
{
// wird ein kleineres Element gefunden, so wird dessen Index gemerkt
minStelle = stelle;
}
}
// das gefundene kleinste Element wird nach vorne (auf den Platz mit
// dem Index durchgang) getauscht, sofern es nicht schon dort steht:
if (minStelle > durchgang)
{
tausche (durchgang, minStelle);
}
}
}
public String aufDisk (String dateiName)
//schreibt alle Autos des Fuhrparks unter dateiName auf Disk
{
ObjectOutputStream oos;
String meldung = "";
try
{
oos = new ObjectOutputStream(new FileOutputStream (dateiName));
//öffnet die Datei zum Schreiben. Evtl. alte Datei wird überschrieben.
for (int i=0; i<anzahlDerAutos; i++) //geht ganzen Fuhrpark durch
{
oos.writeObject (fuhrpark[i]); //schreibt jeweils ein Auto vom Typ Kfz
}
oos.close(); //schließt die Datei
meldung = ""+anzahlDerAutos+" Auto(s) in '"+dateiName+"' gespeichert.\n";
}
catch (IOException ex)
{
meldung = "Fehler beim Speichern: "+ex+"\n";
}
return (meldung); //gibt Erfolgs- oder Fehlermeldung zurück
}
public String vonDisk (String dateiName)
//ersetzt den bisherigen Fuhrpark durch die Autos von Disk
{
ObjectInputStream ois;
String meldung = "";
int i = 0; //hier deklariert, damit noch nach for-Schleife verfügbar
try
{
ois = new ObjectInputStream(new FileInputStream(dateiName));
//öffnet Datei zum Lesen (Fehler, falls nicht gefunden)
try
{
for (i=0; i<25; i++) //Schleife wird durch EOF abgebrochen!
{
fuhrpark[i] = (Kfz) ois.readObject (); //liest ein Auto
}
//Diese Stelle wird nie erreicht: Durch EOF aus Schleife in catch
}
catch (EOFException eex) //Fehler entsteht durch Dateiende
{
ois.close(); //Datei schließen
anzahlDerAutos = i; //anzahlDerAutos = gelesene Zahl
//letztes gelesenes Auto hat Wert null => nicht berücksichtigen,
//also nicht anzahlDerAutos = i+1;
meldung = ""+anzahlDerAutos+" Auto(s) aus Datei '"+dateiName
+"' gelesen.";
}
}
catch (Exception ex) // nicht nur IO-, auch ClassNotFound-Exception!
{
meldung = "Fehler beim Lesen: "+ex+"\n";
}
return (meldung);
}
public String listeAlle()
//Erzeugt Text mit den Daten aller Fahrzeuge: 1 Zeile pro Auto
{
String ausgabe = "";
for (int i=0; i<anzahlDerAutos; i++)
{
ausgabe = ausgabe+(i+1)+".) "+fuhrpark[i].nennen()+"\n";
} //nutzt Kfz-Methode
return (ausgabe);
}
}
zum Seitenanfang / zum Seitenende
//Kfz-Verwaltung, Datei 3/4
//Java JDK 1.1.18 -- Krell 21.2.2002/5.3.02
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//Benutzer-Oberfläche der Kfz-Verwaltung, die ihrerseits ein Objekt
//namens alleAutos der Klasse KfzFuhrpark anlegt und verwaltet
public class KfzGUI extends Frame
{
KfzFuhrpark alleAutos = new KfzFuhrpark(); //Def. und Erzeugen
TextField tfKennzeichen = new TextField("",10);
TextField tfHersteller = new TextField("",20);
TextField tfModell = new TextField("",17);
TextField tfBaujahr = new TextField("",6);
TextField tfKmStand = new TextField("",8);
TextField tfDateiname = new TextField("KfzDatei.Dat",15);
Button btNeuesAuto = new Button("Auto neu aufnehmen");
Button btNeueKm = new Button("km-Stand eines vorhandenen Autos ändern (*)");
Button btLöschen = new Button("Auto löschen (^)");
Button btHersteller = new Button("Alle Autos eines Herstellers (%) finden");
Button btSortNr = new Button("Autos nach Nummer sortieren");
Button btSortKm = new Button("Autos nach km sortieren");
Button btSpeichern = new Button("Fuhrpark speichern");
Button btLaden = new Button("Fuhrpark laden");
Button btZeigen = new Button("Fuhrpark zeigen");
TextArea taAusgabe = new TextArea(9,75);
public void richteFensterEin() // Fenster initalisieren und beschreiben
{
//WindowsListener hinzufügen, damit Schließknopf funktioniert
addWindowListener (
new WindowAdapter ()
{
public void windowClosing (WindowEvent ereignis)
{ //ersetzt bisher leere Methode
setVisible (false);
dispose();
System.exit(0);
}
}
); // runde Klammer vom Windowlistener geschlossen;
}
public void richteKnöpfeEin()
{
btNeuesAuto.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
taAusgabe.setText ("Bitte alle Felder ausfüllen -- Ganze Zahlen bei
Baujahr und km-Stand!");
alleAutos.neuesAuto (tfKennzeichen.getText(), tfHersteller.getText(),
tfModell.getText(), Integer.parseInt(tfBaujahr.getText()),
Integer.parseInt(tfKmStand.getText())); //Auto aufnehmen
taAusgabe.setText ("Auto "+tfKennzeichen.getText()+" aufgenommen!\n");
tfKennzeichen.setText(""); //und Eingabefelder löschen
tfHersteller.setText("");
tfModell.setText("");
tfBaujahr.setText("");
tfKmStand.setText("");
}
}); //runde Klammer (von btNeuesAuto.addActionListener)
btNeueKm.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
taAusgabe.setText ("Bitte Kennzeichen eingeben und eine ganze Zahl für
den (neuen) km-Stand!");
taAusgabe.setText(alleAutos.ändereKmStand (tfKennzeichen.getText(),
Integer.parseInt(tfKmStand.getText()))); //km ändern, Erfolg melden
tfKennzeichen.setText(""); //und Eingabefelder löschen
tfKmStand.setText("");
}
}); //runde Klammer (von btNeueKm.addActionListener)
btLöschen.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
taAusgabe.setText(alleAutos.löschen (tfKennzeichen.getText()));
//Auto löschen, Erfolg melden
tfKennzeichen.setText(""); //und Eingabefeld löschen
}
}); //runde Klammer (von btLöschen.addActionListener)
btHersteller.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
taAusgabe.setText(alleAutos.listeAutosVon (tfHersteller.getText()));
tfHersteller.setText(""); //und Eingabefeld löschen
}
}); //runde Klammer (von btHersteller.addActionListener)
btSortNr.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
alleAutos.minSortNr ();
taAusgabe.setText("Autos wurden lexikografisch nach Kennzeichen
sortiert");
}
}); //runde Klammer (von btSortNr.addActionListener)
btSortKm.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
alleAutos.minSortKm ();
taAusgabe.setText("Autos wurden nach dem km-Stand sortiert");
}
}); //runde Klammer (von btSortKm.addActionListener)
btSpeichern.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{ //alle Autos auf Disk speichern
taAusgabe.setText( alleAutos.aufDisk (tfDateiname.getText()));
}
}); //runde Klammer (von btSpeichern.addActionListener)
btLaden.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{ //alle Autos von Disk lesen
taAusgabe.setText( alleAutos.vonDisk (tfDateiname.getText()));
}
}); //runde Klammer (von btLaden.addActionListener)
btZeigen.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{ //Liste aller Autos anzeigen
taAusgabe.setText( alleAutos.listeAlle() );
}
}); //runde Klammer (von btZeigen.addActionListener)
} //Ende von richteKnöpfeEin
public void führeAus ()
{
setTitle("Fuhrpark-Verwaltung"); // Fenster-Titel
setSize (600,350); // Fenstergröße (Breite und Höhe in Pixeln)
setLayout (new FlowLayout());
richteFensterEin();
richteKnöpfeEin();
add (new Label("Amtliches Kennzeichen (*,^):"));
add (tfKennzeichen);
add (new Label("Fahrzeughersteller (%):"));
add (tfHersteller);
add (new Label("Modell:"));
add (tfModell);
add (new Label("Baujahr:"));
add (tfBaujahr);
add (new Label("Aktueller Stand (*):"));
add (tfKmStand);
add (new Label("km."));
add (btNeuesAuto);
add (btNeueKm);
add (btLöschen);
add (btHersteller);
add (btSortNr);
add (btSortKm);
add (new Label("Dateiname:"));
add (tfDateiname);
add (btSpeichern);
add (btLaden);
add (new Label(" "));
add (btZeigen);
add (taAusgabe);
setVisible(true);
}
}
zum Seitenanfang / zum Seitenende
//Kfz-Verwaltung, Datei 4/4
//Java JDK 1.1.18 -- Krell 21.2.2002
//Definiert, erzeugt und startet ein Objekt der Klasse KfzGUI
public class KfzStart extends java.applet.Applet
{
//Start als selbständige Application
public static void main (String[] s)
{
KfzGUI autoVerw = new KfzGUI();
autoVerw.führeAus();
}
//Start als Applet aus dem Web-Browser
public void init()
{
KfzGUI autoVerw = new KfzGUI();
autoVerw.führeAus();
}
}
zum Seitenanfang / zum Seitenende
Verbesserungsvorschlag 2003:
vergleicheMit mit Auswahl eines Sortierkriteriums
Gerade nach den anfängliche Ausführungen über vernünftige Klasseneinteilungen (s.o.) ist es eigentlich nicht einzusehen, warum oben in der Klasse KfzFuhrpark zwei Sortier-Methoden implementiert wurden - die Sortierung nach dem Kfz-Kennzeichen bzw. die Sortierung nach dem Kilometerstand. Schließlich handelt es sich bei Nummer und km-Stand um Eigenschaften des Autos, die in der Klasse Kfz stehen und nicht in KFzFuhrpark. Außerdem ist der Algorithmus beider Sortierverfahren identisch - nur eine Zeile mit dem Vergleich unterscheidet sich. Es erscheint daher sinnvoll, eine Methode vergleicheMit innerhalb der Klasse Kfz anzusiedeln, die dann aus der Klasse KfzFuhrpark in einem einzigen, allgemeinen Sortierverfahren benutzt werden kann (der Name vergleicheMit lag nahe, weil es für Zeichenketten [Strings] in Java bereits eine mitgelieferte Methode compareTo gibt, die ähnlich zu nutzen ist). vergleicheMit gehört auch deshalb in die Klasse Kfz, weil schon ein einzelnes Fahrzeug mit einem anderen verglichen werden kann. Es bedarf dazu nicht der Reihung, die typisch für den KfzFuhrpark ist.
Die Methode vergleicheMit müsste nun einen Parameter erhalten, mit dem man das Sortier- bzw. Vergleichskriterium wählen kann - ob also zwei Autos (bzw. das aktuelle Objekt mit einem weiteren, als Parameter angegebenen Auto) hinsichtlich der Nummer oder des km-Standes oder vielleicht noch bezüglich einer anderen Eigenschaft des Fahrzeugs/der Fahrzeuge verglichen werden sollen. Da der Vergleich zu einer Reihenfolge führen muss, liegt es nahe, wie bei compareTo ein numerisches Ergebnis zurück zu geben: eine negative Zahl bedeutet, dass das aktuelle Auto bezüglich des Kriteriums vor dem übergeben Auto stehen muss. Das Ergebnis 0 bedeutet Gleichrangigkeit, und bei positivem Ergebnis gehört das aktuelle Auto hinter das Parameter-Auto bei einem Ranking nach dem ausgewählten Kriterium.
Die Kriteriumsauswahl kann beliebig kompliziert erfolgen: Am saubersten wäre wohl die Vereinbarung eines Interfaces, das Konstanten zur Auswahl verschiedener Kfz-Eigenschaften enthält. Die Klassen Kfz und KfzFuhrpark und auch die Oberfläche könnten dann dieses Interface implementieren.
Für einen ersten Zugang reicht aber evtl. auch die Auswahl über einen Kennbuchstaben, z.B. 'n' = Nummer und 'k' = km-Stand. Damit würde dann die Kfz-Datei oben um folgende Methode ergänzt:
public int vergleicheMit (Kfz anderesAuto, char
kriterium)
//Vergleicht
Autos bzgl. der ausgewählten Eigenschaft
{
switch (kriterium)
{
case 'n' : return (kennzeichen.compareTo (anderesAuto.kennzeichen));
case 'k' : return (kmStand - anderesAuto.kmStand);
}
}
Ein break nach dem case ist wegen des returns nicht nötig (und auch nicht mehr erlaubt).
Innerhalb der Klasse KfzFuhrpark gäbe es dann nur noch eine einzige Sortiermethode. Die veränderten Teile sind kursiv:
public void minSort (char kriterium) // MinSort nach angegebenem
Kriterium
// Sortieren durch Auswahl des jeweils kleinsten Elements im Rest
// und Tausch dieses Elements nach vorne. Nach dem 0. Durchgang steht
// also das kleinste Element ganz links auf Platz 0, beim nächsten Durchgang
// kommt das nächtkleinere Element auf Platz 1 usw., so dass die Sortierung
// von links nach rechts wächst
{
int minStelle, durchgang, stelle;
for (durchgang=0; durchgang<anzahlDerAutos; durchgang++)
{
minStelle = durchgang; // vorderstes El. im unsortierten Teil zum Vergleich
for (stelle=durchgang+1; stelle<anzahlDerAutos; stelle++)
{
if (fuhrpark[stelle].vergleicheMit(fuhrpark[minStelle], kriterium)<0)
{
// wird ein kleineres Element gefunden, so wird dessen Index gemerkt
minStelle = stelle;
}
}
// das gefundene kleinste Element wird nach vorne (auf den Platz mit
// dem Index durchgang) getauscht, sofern es nicht schon dort steht:
if (minStelle > durchgang)
{
tausche (durchgang, minStelle);
}
}
}
Und in der Oberfläche KfzGUI müssten dann die beiden Aufrufe aus den Knopf-Methoden abgeändert werden:
btSortNr.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
alleAutos.minSort ('n');
taAusgabe.setText("Autos wurden lexikografisch nach Kennzeichen
sortiert");
}
}); //runde Klammer (von btSortNr.addActionListener)
btSortKm.addActionListener (
new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
alleAutos.minSort ('k');
taAusgabe.setText("Autos wurden nach dem km-Stand sortiert");
}
}); //runde Klammer (von btSortKm.addActionListener)
So erscheint mir das Programm jetzt viel eleganter, zumal sich (durch weitere case-Fälle) leicht weitere Kriterien beim Kfz hinzufügen lassen, ohne den KfzFuhrpark zu beeinflussen. vergleicheMit lässt sich selbstverständlich auch mit jeder Suche bestens verwenden!
zurück zur Informatik-Hauptseite
(Die anderen „Informatik mit Java"-Seiten werden entweder mit dem Menü hier am
Seitenanfang oder
am besten auch auf der Informatik-Hauptseite ausgewählt)