Ludwig-Maximilians-Universität München Institut für Informatik Prof. Dr. Christian Böhm Annahita Oswald, Bianca Wackersreuther München, 18.12.2009 Einführung in die Programmierung WS 2009/10 Übungsblatt 9: Objekt-Orientierung Besprechung: 11./13./14./15.01.10 Dieses Blatt geht nicht in die Bonusregelung ein. Aufgabe 9-1 0 Punkte Objektorientierter Entwurf Gegeben ist folgendes UML-Klassendiagramm zur Modellierung von Flugbuchungen: Flug * - nummer : int 1 Flugzeug - typ : String - anzahlPlaetze : int + Flug(int, Pilot, Flugzeug) + buchen(Passagier) : boolean + stornieren(Passagier) : boolean + getAnzahlPassagiere() : int - freierPlatz() : Platz + Flugzeug(String, int) + getAnzahlPlaetze() : int + getTyp() : String * 1 Passagier Pilot 1 Platz - name : String - name : String - nummer : int + Pilot(String) + getName() : String + Passagier(String) + getName() : String + Platz(int) + getPassagier() : Passagier + setPassagier(Passagier) : void + getNummer() : int Implementieren Sie diese Klassen in Java. 1 Lösungsvorschlag: /** * Klasse zur Modellierung eines Sitzplatzes. */ public class Platz { /** * Die Nummer des Platzes */ private int nummer; /** * Der Passagier, der diesen Platz gebucht hat */ private Passagier passagier; /** * Erzeugt einen Platz mit der angegebenen Platznummer. * * @param nummer die Nummer des Platzes */ public Platz(int nummer){ this.nummer = nummer; } /** * Gibt den Passagier, des diesen Platz gebucht hat, zur&uuml;ck. * * @return der Passagier, der diesen Platz gebucht hat */ public Passagier getPassagier(){ return this.passagier; } /** * Bucht diesen Platz f&uml;r den angegebenen Passagier. * * @param passagier der Passagier, der auf diesen Platz gebucht wird */ public void setPassagier(Passagier passagier){ this.passagier = passagier; } /** * Gibt die Nummer dieses Platzes zur&uuml;ck. * * @return die Nummer dieses Platzes */ public int getNummer(){ return this.nummer; } } 2 /** * Klasse zur Modellierung eines Flugzeugs. */ public class Flugzeug { /** * Der Typ dieses Flugzeugs */ private String typ; /** * Die Anzahl m&ouml;glicher Pl&auml;tze in diesem Flugzeug */ private int anzahlPlaetze; /** * Erzeugt ein neues Flugzeug mit dem angebenen Typ und * der angegebenen Anzahl von Pl&auml;tzen. * * @param typ der Typ dieses Flugzeugs * @param anzahlPlaetze die Anzahl m&ouml;glicher Pl&auml;tze * in diesem Flugzeug */ public Flugzeug(String typ, int anzahlPlaetze){ this.typ = typ; this.anzahlPlaetze = anzahlPlaetze; } /** * Gibt die Anzahl von m&ouml;glichen Pl&auml;tzen in * diesem Flugzeug zur&uuml;ck. * * @return die Anzahl m&ouml;glicher Pl&auml;tze */ public int getAnzahlPlaetze(){ return this.anzahlPlaetze; } /** * Gibt den Flugzeug-Typ aus. * * @return der Flugzeug-Typ */ public String getTyp(){ return this.typ; } } 3 /** * Klasse zur Modellierung eines Piloten. */ public class Pilot { /** * Der Name dieses Piloten. */ private String name; /** * Erzeugt einen Piloten mit dem angegebenen Namen. * * @param name der Name des Piloten */ public Pilot(String name){ this.name = name; } /** * Gibt den Namen dieses Piloten zur&uuml;ck. * * @return der Name des Piloten */ public String getName(){ return this.name; } } /** * Klasse zr Modellierung eines Passagiers. */ public class Passagier { /** * Der Name dieses Passagiers */ private String name; /** * Erzeugt einen Passagier mit dem angegebenen Namen. * * @param name der Name des Passagiers */ public Passagier(String name){ this.name = name; } /** * Gibt den Namen dieses Passagiers zur&uuml;ck. * * @return der Name dieses Passagiers */ public String getName(){ return this.name; } } 4 /** * Klasse zur Modellierung eines Flugs. */ public class Flug { /** * Die Flugnummer */ private int nummer; /** * Der Pilot dieses Flugs */ private Pilot pilot; /** * Die Pl&auml;tze f&uuml;r diesen Flug */ private Platz[] platz; /** * Erzeugt einen neuen Flug mit der gegebenen Flugnummer und dem gegebenen * Piloten und Flugzeug. * * @param nummer die Flugnummer * * @param pilot der Pilot des Flugs * * @param flugzeug das Flugzeug f&uuml;r diesen Flug * */ public Flug(int nummer, Pilot pilot, Flugzeug flugzeug) { this.nummer = nummer; this.pilot = pilot; this.platz = new Platz[flugzeug.getAnzahlPlaetze()]; for (int i = 0; i < this.platz.length; i++) { this.platz[i] = new Platz(i + 1); } } /** * Bucht f&uuml;r einen gegebenen Passagier einen Platz in diesem Flug. * * @param passagier Passagier, f&uuml;r den ein Platz gebucht werden soll * @return Konnte ein Platz gebucht werden? * / * public boolean buchen(Passagier passagier) { Platz platz = freierPlatz(); if (platz != null) { platz.setPassagier(passagier); return true; } return false; } 5 /** * Storniert den f&uuml;r einen gegebenen Passagier gebuchten Platz in * diesem Flug. * * @param passagier Passagier, f&uuml;r den ein gebuchter Platz storniert werden * soll * * @return Konnte der Flug erfolgreich storniert werden? */ public boolean stornieren(Passagier passagier) { for (Platz platz : this.platz) { if (platz.getPassagier() == passagier) { platz.setPassagier(null); return true; } } return false; } /** * Gibt einen freien Platz f&uuml;r diesen Flug zur&uuml;ck. * * @return einen freien Platz f&uuml;r diesen Flug, <code>null</code>, falls kein Platz mehr frei ist. * */ private Platz freierPlatz() { for (int i = 0; i < this.platz.length; i++) { if (this.platz[i].getPassagier() == null) { return this.platz[i]; } } return null; } /** * Gibt die Anzahl der Passagiere aus, die f&uuml;r diesen Flug einen Platz * gebucht haben. * * @return die Anzahl der Passagiere in diesem Flug */ public int getAnzahlPassagiere() { int anzahl = 0; for (Platz platz : this.platz) { if (platz.getPassagier() != null) { anzahl++; } } return anzahl; } } 6 Aufgabe 9-2 Verbunde: Klassen / Objekte ohne Methoden Die Datei StudentenInfo.java hat folgenden Inhalt: public class StudentenInfo { public static void main(String[] args) { Student a = new Student("Peter", "Parker", new Datum(15, 8, 1962), "parkerp"); Student b = new Student("Mary Jane", "Watson", new Datum(4, 11, 1966), "watsonma"); System.out.println("Name: " + a.nachname + ", " + a.vorname); System.out.println("Kennung: " + a.kennung); System.out.println("Geboren am: " + a.geburtsdatum.tag + "." + a.geburtsdatum.monat + "." + a.geburtsdatum.jahr); System.out.println("Name: " + b.nachname + ", " + b.vorname); System.out.println("Kennung: " + b.kennung); System.out.println("Geboren am: " + b.geburtsdatum.tag + "." + b.geburtsdatum.monat + "." + b.geburtsdatum.jahr); } } (a) Lassen Sie die Klasse StudentenInfo unverändert und definieren Sie dazu passende Klassen Student und Datum. Für diese Klassen brauchen Sie keine Methoden zu definieren. Lösungsvorschlag: /** * Klasse zur Modellierung eines Studenten. */ public class Student { /** * Der Vorname des Studenten. */ public String vorname; /** * Der Nachname des Studenten. */ public String nachname; /** * Das Geburtsdatum des Studenten. */ public Datum geburtsdatum; /** * Die Kennung des Studenten. */ public String kennung; 7 /** * Erzeugt einen Studenten mit den angegebenen Daten. * * @param vorname der Vorname des Studenten * * @param nachname der Nachname des Studenten * * @param gebDatum das Geburtsdatum des Studenten * * @param kennung die Kennung des Studenten * */ public Student(String vorname, String nachname, Datum gebDatum, String kennung) { this.vorname = vorname; this.nachname = nachname; this.geburtsdatum = gebDatum; this.kennung = kennung; } } /** * Klasse zur Modellierung eines Datums in numerischer Form. Ein Datum wird * durch Tag, Monat und Jahr repr&auml;sentiert. */ public class Datum { /** * Tag */ public int tag; /** * Monat */ public int monat; /** * Jahr */ public int jahr; /** * Erzeugt ein Datum mit den angegebenen Werten f&uuml;r Tag, Monat und * Jahr. * * @param tag Tag * @param monat * Monat * @param jahr * Jahr * / * public Datum(int tag, int monat, int jahr) { this.tag = tag; this.monat = monat; this.jahr = jahr; } } 8 (b) Erklären Sie, warum die Klassen Student und Datum nicht gutem objektorientiertem Programmierstil entsprechen. Wie könnte man dies verbessern? Lösungsvorschlag: Das Prinzip der Kapselung wurde in den beiden Klassen Student und Datum nicht umgesetzt, da die Attribute der Klassen jeweils als public deklariert wurden und somit auch außerhalb der Klasse sichtbar und veränderbar sind. Dies kann verhindert werden, indem man die Attribute als private deklariert und einen Zugriff auf die Attribute nur durch klar definierte Schnittstellen, d.h. Methoden, ermöglicht. So, wie die Klassen jetzt sind, verwirklichen Sie den allgemeinen Datentyp “Verbund” (oder “Record”). Dies ist in sich sinnvoll, aber es werden eben noch nicht alle Möglichkeiten der Objekt-Orientierung genutzt. Vor allem wird kein “Verhalten” der Objekte modelliert. Aufgabe 9-3 0 Punkte Weihnachtsbäume aus Strings Erstellen Sie eine Klasse Weihnachtsbaum, die Weihnachtsbäume unterschiedlicher Höhe repräsentiert. (a) Jeder Weihnachtsbaum sei durch folgende Attribute definiert: • Weihnachtsbaumspitze (repräsentiert durch den String "*", wird nie verändert) • Weihnachtsbaumstamm (repräsentiert durch den String "[_]", wird nie verändert) • Höhe des Baums (b) Definieren Sie einen Konstruktor Weihnachtsbaum(int hoehe), der eine beliebige Höhe des zu erzeugenden Weihnachtsbaums als Parameter erhält. (c) Die Klasse Weihnachtsbaum soll eine Methode public String zeichne() enthalten, die den Weihnachtsbaum graphisch ausgibt. Ein Beispiel für einen Weihnachtsbaum der Höhe 5 finden Sie in der unten angegebenen Abbildung. Sie können sich hier auch weitere Hilfsmethoden implementieren. Testen Sie Ihr Programm. Lösungsvorschlag: public class Weihnachtsbaum { public static final String WEIHNACHTSBAUMSPITZE = "*"; public static final String WEIHNACHTSBAUMSTAMM = "[_]"; private int hoehe; public Weihnachtsbaum(int hoehe) { this.hoehe = hoehe; } 9 public String zeichne() { StringBuilder builder = new StringBuilder(); builder.append(fuellen(this.hoehe + 1, " ")); builder.append(WEIHNACHTSBAUMSPITZE); builder.append(fuellen(this.hoehe + 1, " ")); builder.append("\n"); for (int i = this.hoehe; i > 0; i--) { builder.append(fuellen(i, " ")); builder.append("/"); builder.append(abwechselndFuellen(this.hoehe - i + 1, ".", ",")); builder.append("\\"); builder.append(fuellen(i, " ")); builder.append("\n"); builder.append(fuellen(i - 1, " ")); builder.append("/"); builder.append(abwechselndFuellen(this.hoehe - i + 2, ",", ".")); builder.append("\\"); builder.append(fuellen(i - 1, " ")); builder.append("\n"); } builder.append(fuellen(this.hoehe, "ˆ")); builder.append(WEIHNACHTSBAUMSTAMM); builder.append(fuellen(this.hoehe, "ˆ")); builder.append("\n"); return builder.toString(); } private String abwechselndFuellen(int laenge, String fuellstring1, String fuellstring2) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < laenge; i++) { appendString(fuellstring1, builder); if (i + 1 < laenge) { appendString(fuellstring2, builder); } } return builder.toString(); } private void appendString(String string, StringBuilder builder) { builder.append(string); } private String fuellen(int laenge, String fuellstring) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < laenge; i++) { builder.append(fuellstring); } return builder.toString(); } public static void main(String[] args) { Weihnachtsbaum xmastree = new Weihnachtsbaum(5); System.out.println(xmastree.zeichne()); } } 10