TU Kaiserslautern Prof. Dr. A. Poetzsch-Heffter Dipl.-Inf. J.-M. Gaillourdet Fachbereich Informatik Dipl.-Inf. P. Michel AG Softwaretechnik Übungsblatt 13: Software-Entwicklung 1 (WS 2009/10) Ausgabe: in der Woche vom 01.02. bis zum 05.02. Abgabe: in der Woche vom 08.02. bis zum 12.02. Abnahme: max. zwei Tage nach der Übung Aufgabe 1 Listen und Iteratoren (Präsenzaufgabe) Lesen Sie die Teilaufgaben von Aufgabe 2 und entwerfen Sie ein Klassendiagramm mit allen Klassen, Methoden, Attributen und Beziehungen. Aufgabe 2 Listen und Iteratoren (Einreichaufgabe) a) Implementieren Sie doppelt verkettete Listen mit Anker, wie auf Folie 1090 angedeutet. Ihre Klasse LinkedList soll entsprechende Methoden zu denen aus der Klasse SLinkedList besitzen und außerdem folgende implementieren: void addLast (int n) int removeLast () Nutzen Sie die doppelte Verkettung, um auch diese beiden Operationen in konstanter Zeit ausführen zu können, d.h. unabhängig von der Anzahl der Elemente in der Liste. Hinweis: Bei einer Implementierung mit Anker verwendet man ein zusätzliches Entry-Element ohne Wert, damit auch im Fall der leeren Liste die header-Komponente von LinkedList nicht null ist. Damit muss dieser Fall nicht speziell behandelt werden und Ihre Implementierung wird auch sonst vereinfacht. b) Implementieren Sie eine Iterator-Klasse für Ihre Listen-Implementierung gemäß Folie 1095ff. Auch hier soll der Iterator für doppelt verkettete Listen mehr Methoden implementieren als auf den Folien: boolean hasPrevious () int previous () void remove () // Entfernt das aktuelle Element aus der Liste Machen Sie sich mit der Semantik der Iterator-Methoden in der Java API vertraut, insbesondere mit der der beiden Methoden remove und previous. Lesen Sie dazu die Dokumentation der ListIterator-Klasse http://java.sun.com/javase/6/docs/api/java/util/ListIterator.html. Hinweis: In einer Implementierung mit Anker gibt es genau n + 1 “Zwischenräume” zwischen EntryElementen, was für die Implementierung des Iterators also ebenfalls sehr hilfreich ist! c) Überlegen Sie sich, was mögliche Vor- und Nachbedingungen für Ihre Methoden aus a) und b) sein könnten und annotieren Sie diese mit boolschen Java-Ausdrücken oder, wenn nicht anders möglich, umgangssprachlich. Orientieren Sie sich an requires, modifies und ensures Annotationen von den Folien. Beschreiben Sie kurz einige gültige und ungültige Methodenaufruf-Sequenzen. Aufgabe 3 Klassenattribute und -methoden (Einreichaufgabe) a) Machen Sie sich mit der Schnittstelle der Klasse Math vertraut (Beschreibung auf http://java.sun. com/javase/6/docs/api/java/lang/Math.html. Begründen Sie, warum statische Attribute / Methoden verwendet wurden. b) Warum kann folgendes Programm nicht kompiliert werden? Schreiben Sie es so um, dass es kompiliert. class Main { int wert; public static void main( String [] args) { Main m = new Main (); Main.wert = 7; System .out. println (wert); } } c) Implementieren Sie eine Klasse Count, die eine statische Methode print() besitzt, welche ausgibt, wie viele Objekte der Klasse Count bis dato instanziiert worden sind. Aufgabe 4 Umsetzung von UML Diagrammen (Einreichaufgabe) Im Folgenden modellieren Sie eine Stadt bestehend aus Stadtteilen, Straßen, Häusern und einem Park. Stadtteile können direkt an andere Stadtteile angrenzen. Straßen führen durch Stadtteile und eventuell auch am Park entlang. Häuser liegen in einem Stadtteil und liegen entweder an einer Straße oder einer Kreuzung von zwei Straßen. Der Park liegt in einem Stadtteil. a) Modellieren Sie diese Stadt als Klassendiagramm mit Beziehungen. Wählen Sie gute Namen für die Beziehungen und legen Sie sinnvolle Multiplizitäten fest. b) Nun verfeinern wir den Entwurf. Schreiben Sie Java-Klassen die zeigen, wie Sie die Beziehung zwischen Stadtteil und Haus mit Attributen realisieren würden. Entwerfen Sie außerdem vier unterschiedliche Realisierungen der Beziehung zwischen Stadtteil und Straße. Was sind die Unterschiedlichen Vor- und Nachteile der Varianten. Wovon würden Sie die Entscheidung für eine der Varianten abhängig machen? Aufgabe 5 Parametrische Typen (Einreichaufgabe) Implementieren Sie eine parametrische Fassung der Klasse LinkedList aus Aufgabe 2, Teil a) und b). Stellen Sie dabei sicher, dass Ihre Implementierung ohne Warnungen übersetzt! Hinweis: Um alle Warnungen angezeigt zu bekommen müssen Sie den Java Compiler mit der Option -Xlint aufrufen, also z.B. javac -Xlint LinkedList.java. Aufgabe 6 Grafikeditor (Präsenzaufgabe) Lesen Sie die Teilaufgaben von Aufgabe 7 und entwerfen Sie ein Klassendiagramm mit allen Klassen, Methoden, Attributen und Beziehungen. Aufgabe 7 Grafikeditor (Einreichaufgabe) In dieser Aufgabe geht es darum, einen Editor für graphisch darstellbare Komponenten zu implementieren. Der Editor hat ein Zeichenfeld, das über x und y-Koordinaten angesprochen wird. Die Bedienung des Editors erfolgt Menü gesteuert in der Kommandozeile. Eine mögliche Sitzung könnte wie folgt aussehen: 1) Neues Polygon anlegen 2) Fokus ändern 3) Verschieben Ihre Wahl: 1 Polygon eingeben: Name: Dreieck Anzahl der Ecken (min 3): 3 Ecke 1: x-Koordinate: 10 y-Koordinate: 10 Ecke 2: x-Koordinate: 10 y-Koordinate: 20 Ecke 3: x-Koordinate: 60 y-Koordinate: 30 1) Neues Polygon anlegen 2) Fokus ändern 3) Verschieben Ihre Wahl: Zur Bearbeitung dieser Aufgabe können Sie sich die Datei “SEGraphics.java” von der Vorlesungsseite laden und übersetzen. SEGraphics bietet Ihnen folgendes: • Der Konstruktor von SEGraphics legt eine Zeichenfläche an. • Die Methode clear löscht den Inhalt einer Zeichenfläche. • drawCircle, drawString und drawLine werden zum Zeichnen auf der Zeichenfläche benutzt. Folgende Teilaspekte sollen bearbeitet werden: a) Entwerfen Sie eine Klasse Point. Der Konstruktor soll die Koordinaten des Punktes als Parameter nehmen. Schreiben Sie eine statische Methode construct, die vom Benutzer die Koordinaten des Punkts erfragt, ein Objekt vom Typ Point erzeugt und zurückgibt. Sie werden auch Methoden brauchen, die einen Punkt verschieben. b) Ein Polygon besteht aus mindestens drei verschiedenen Punkten einer Ebene, die durch Linien miteinander verbunden sind. Entwerfen Sie eine Klasse Polygon, mit der Sie beliebige Polygone verwalten können. Um Polygone später identifizieren zu können, soll jedes Polygon einen Namen haben. Schreiben Sie auch hier eine zusätzliche statische Methode mit dem Namen construct, die vom Benutzer den Namen und die Koordinaten der Eckpunkte erfragt und ein neues Polygon zurückgibt. Außerdem brauchen Sie Methoden und Attribute, um die Position und Farbe des Polygons zu ändern, und um das Polygon auf ein SEGraphics-Objekt zu zeichnen. Verwenden Sie für Farben Objekte der Klasse Color der Java-API. Informationen dazu finden Sie unter http://java.sun.com/javase/6/docs/api/java/awt/Color.html. c) Entwerfen Sie eine Klasse Editor, die eine Menge von Polygonen und eine Zeichenfläche verwaltet. Der Editor soll eine Methode haben, die es dem Benutzer erlaubt, interaktiv Polygone zu erstellen, zu verschieben und zu löschen. Als Besonderheit soll der Editor über einen Fokus verfügen, so dass man ein Polygon auswählt, d.h. ihm den Fokus gibt, und anschließend z.B. mehrere Verschiebungen nacheinander auf diesem Polygon ausführen kann. d) Schreiben Sie ein Hauptprogramm, das einen neuen Editor erzeugt und die Interaktionsmethode aufruft. Aufgabe 8 Basiswissen zur Vorlesung Kreuzen Sie an, ob folgende Aussagen wahr oder falsch sind. Bereiten Sie diese Aufgabe bis zu Ihrer nächsten Übungsstunde vor, so dass Sie bei Unklarheiten nachfragen und die Antworten diskutieren können. wahr falsch Eine Ordnung ist genau dann noethersch, wenn jede aufsteigende Kette stationär wird. Eine Bedingung, die im Vorzustand einer Prozedur gelten muss, kann entsprechend über den Rumpf der Prozedur als gültig angenommen werden. Aus der Vorbedingung true lässt sich die Nachbedingung false für keine Prozedur beweisen. Ein Hoare-Tupel verbindet eine Vorbedingung P mit einer Nachbedingung Q. (N, <) ist eine noethersche Ordnung. (Z, ≤) ist eine noethersche Ordnung. (2N, ≤) ist eine noethersche Ordnung. (2N = {2n | n ∈ N}) Einer Programmvariablen können mehrere Speichervariablen zugeordnet sein. Ein vollständiger gerichteter Graph hat genau doppelt so viele Kanten wie ein vollständiger ungerichteter Graph. Kann die Spezifikation einer Prozedur mit Schleife bewiesen werden, gibt es automatisch unendlich viele Schleifeninvarianten, mit denen der Beweis geführt werden kann.