Gerichteter gewichteter Graph

Werbung
Example 1
User Requirements
GERICHTETER
GEWICHTETER GRAPH –
DESIGNDOKUMENT
Softwareentwicklung Praktikum,
Übungsbeispiel 1
Gruppe 18
Andreas Hechenblaickner [0430217]
Daniela Kejzar [0310129]
Andreas Maller [0431289]
Gruppe 18
Seite 1
User Requirements
1
User Requirements
1.1
Aufgabenstellung
Example 1
Es soll ein gerichteter, gewichteter Graph erstellt werden, welcher aus Knoten
(nodes) und Kanten (edges) besteht. Hierbei sollten Knoten mit anderen
Knoten durch Kanten verbunden werden. Die Datenstruktur sollte verschiedene
Funktionalitäten, wie zB das Einfügen und Löschen von Knoten und Kanten,
aufweisen.
1.2
Anforderungen
Es ist eine geeignete Datenstruktur zu entwickeln, die es ermöglicht die
gewünschten Funktionalitäten zu erfüllen. Das Testprogramm sollte diese
Funktionalitäten zeigen können.
Ein Input-Handler soll die eingegebenen Kommandos verarbeiten und die dazu
entsprechenden Operationen am Graphen durchführen.
Das Programm muss sinnvoll objektorientiert aufgebaut sein.
Seite 2
Gruppe 18
Example 1
Architectural Design
2
Architectural Design
2.1
Module
Das Programm wird in folgende Module aufgeteilt:
Name
Beschreibung
Seite
Modul Graph
Beschreibt die interne Speicherung eines
gerichteten Graphen. Stellt Klassen mit
Methoden zur Manipulation der im Graphen
gespeicherten Knoten und Kanten zur
Verfügung.
4
Modul Input-Handler
Verarbeitet eingegebene Kommandos und
führt die entsprechenden Befehle aus.
7
Modul Testprogramm
Leitet eingegeben Kommandos an den
Input-Handler weiter und gibt
Fehlermeldungen entsprechend an den
Benutzer weiter.
9
Gruppe 18
Seite 3
Modul Graph
Example 1
3
Modul Graph
3.1
Beschreibung
Ein gerichteter gewichteter Graph besteht aus beliebig vielen Knoten die
untereinander durch beliebig viele Kanten verbunden sein können. Jede Kante
hat einen Start- und einen Zielknoten. Start- und Zielknoten können auch
gleich sein – in diesem Fall zeigt ein Knoten auf sich selbst. Ein Graph, jeder
Knoten und jede Kante haben einen Namen. Es dürfen nicht zwei Knoten mit
demselben Namen existieren. Es dürfen weder zwei Kanten mit selbem Namen,
zwischen zwei Knoten existieren, noch dürfen zwei Kanten mit demselben
Namen denselben Knoten als Start- oder Zielknoten haben. Es jedoch erlaubt,
dass mehrere Kanten denselben Namen besitzen, vorausgesetz sie teilen sich
weder Start- noch Zielknonten. Jede Kante speichert zusätzlich noch eine
positive Ganzzahl als Gewichtung. Ein neuer Graph enthält anfangs weder
Knoten noch Kanten.
1
bd
:
ce: 1
ad: 1
Abbildung 1: Beispiel eines Graphen
3.2
Bereitgestellte Klassen
Graph, Node und Edge
Die Klasse Graph speichert einen gerichteten, gewichteten Graphen. Alle
möglichen Operationen wie zB das Einfügen von Knoten und Kanten werden
über public-Methoden bereitgestellt. Die interne Speicherung der Zuordnung
von Kanten und Knoten wird im nächsten Abschnitt Verwendete Datenstruktur
beschrieben.
Seite 4
Gruppe 18
Example 1
Modul Graph
Displayable
Alle anzeigbaren Objekte haben die gemeinsame abstrakte Superklasse
Displayable, die eine Implementierung der virtuellen Methode show erfordert.
In dieser Methode wird einfach die gewünschte Repräsentation der Klasse als
String auf den Standard-Output geschrieben.
Abbildung 2: Klassendiagramm des Moduls Graph
3.3
Verwendete Datenstruktur
Die Knoten werden intern in einem assoziativen Speicher (Template Map aus
der STL) mit dem Name des Knoten und den Knoten selbst als SchlüsselWerte-Paar gespeichert. Diese Datenstruktur wird verwendet da auf diese
Weise einfach verhindert werden kann, das mehrere Knoten mit demselben
Namen im Graphen existieren, und die häufige Operation „Knoten mit einem
bestimmten Namen ermitteln“ kann ohne zeitaufwändiges durchlaufen aller
Knoten durchgeführt werden.
Die Kanten werden intern ebenfalls in Maps gespeichert. Es gibt jedoch im
Graphen keine gesamte Liste, sondern jeder Knoten hält jeweils zwei Maps von
Kanten. Die erste Map speichert alle von diesem Knoten ausgehenden Kanten,
die zweite alle Kanten die diesen Knoten als Ziel haben. Jeder Knoten wird
somit in genau zwei Listen gleichzeitig gehalten. Zusätzlich weiß jede Kante
welche ihre Start- und Zielknoten sind. Durch diese Speicherung wird auch hier
einerseits das schnelle Ansprechen einer bestimmten Kante über ihren Namen
ermöglicht sowie das Einfügen von zwei gleichnamigen Kanten innerhalb eines
Knotens verhindert. Für die korrekte An- und Abmeldung der Kanten bei den
entsprechenden Knoten ist die Kante selbst verantwortlich.
Wird ein Knoten gelöscht der von einer Kante als Start- oder Zielknoten
verwendet wird, so muss auch diese Kante gelöscht werden. Wird eine Kante
gelöscht, ist es notwendig die Verweise aus den Listen des Start- und des
Zielknotens zu entfernen.
Gruppe 18
Seite 5
Modul Graph
Der
Example 1
zuvor
dargestellte
gerichtete
Graph
wird
daher
folgendermaßen
gespeichert:
Graph
Key
Value
"A"
*Node A
"B"
*Node B
"C"
*Node C
"D"
*Node D
"E"
*Node E
Node A
Key
Value
"ab"
*Edge ab
"ad"
*Edge ad
Edge ab
Source Edges
Source
*Node A
Destination
*Node B
Edge ad
Destination Edges
Nodes
Node B
Key
Value
Key
Value
"bd"
*Edge bd
"ab"
*Edge ab
"bc"
*Edge bc
"cb"
*Edge cb
Source Edges
Destination Edges
Source
*Node A
Destination
*Node D
Edge bd
Source
*Node B
Destination
*Node D
Node C
Edge cb
Key
Value
Key
Value
"cb"
*Edge cb
"bc"
*Edge bc
"ce"
*Edge ce
Source Edges
Source
*Node C
Destination
*Node B
Destination Edges
Edge ...
Node ...
Abbildung 3: Interne Speicherung eines Graphen
3.4
Fehlerbehandlung
Zur Fehlerbehandlung werden folgende Exceptions zur Verfügung gestellt:
Exception
GraphException
Seite 6
Beschreibung / Fehlermeldung
Abstrakte Basisklasse für alle Fehlerfälle
die in einem Graph auftreten können.
NodeAlreadyExistsException
error: node already exists
EdgeAlreadyExistsException
error: edge already exists in this context
NoSuchNodeException
error: no such node in graph
NoSuchEdgeException
error: no such edge
Gruppe 18
Example 1
Modul Input-Handler
4
Modul Input-Handler
4.1
Beschreibung
Aufgaben des Input-Handlers ist es eingelesene Kommandos zu verarbeiten
und die entsprechenden Befehle mit ihren Parametern auszuführen. Ungültige
Kommandos
und
Fehler
beim
Ausführen
der
Befehle,
zB
durch
unvollständige/falsche Parameter, werden an das aufrufende Modul gemeldet.
4.2
Bereitgestellte Klassen
InputHandler
Die Klasse InputHandler verarbeitet eingelesene Kommandozeilen. Diese
werden von außen (im Übungsbeispiel vom Modul Testprogramm) mittels der
Methode handleInput als String übergeben.
Der Input-Handler speichert eine Liste aller möglichen Befehle und deren
zugehörige
Objekte
einer
Command-Klasse
(Ableitung
der
Klasse
BaseCommand), welche in der virtuellen Methode executeCommand die für diesen
Befehlt auszuführenden Anweisungen enthalten. Die Klasse InputHandler ist
eine abstrakte Basisklasse, die selbst noch keine Befehle kennt, erst ein Objekt
der Klasse GraphInputHandler kennt alle für einen Graph relevanten Befehle.
Abbildung 4: Klassendiagramm des Input-Handlers
Gruppe 18
Seite 7
Modul Input-Handler
Example 1
GraphInputHandler
Der GraphInputHandler stellt Befehle zur Manipulation eines Graphen zur
Verfügung. Zur Konstruktion muss ein Graph-Objekt übergeben werden. Der
GraphInputHandler
kann
folgende
Befehle
verarbeiten
und
auf
den
zugehörigen Graphen anwenden:
Kommando
add node <name>...
4.3
Beschreibung
Neue(n) Knoten einfügen.
add edge <src> <dst> <name>
<weigth>...
Neue Kante(n) einfügen.
delete node <name>...
Bestimmte(n) Knoten löschen.
delete edge <src <dst>
<name>...
Bestimmte Kante(n) löschen.
show [<node>]
Alle Kanten die einen bestimmten Knoten
als Start- oder Zielknoten haben
anzeigen. Wird kein Knoten angegeben,
wird er gesamte Graph angezeigt.
quit
Veranlasst das aufrufende Modul das
Programm zu beenden.
Fehlerbehandlung
Zur Fehlerbehandlung werden folgende Exceptions zur Verfügung gestellt:
Exception
InputHandlerException
4.4
Beschreibung / Fehlermeldung
Abstrakte Basisklasse für alle Fehlerfälle
die im Input-Handler auftreten können.
InvalidArgumentException
error: invalid argument(s)
UnknownCommandException
error: unknown command
Weitere Designentscheidungen
StringTokenizer
Zur einfachen Verarbeitung der übergeben Befehlszeile wird diese zunächst von
einer eigenen Klasse StringTokenizer in ihre einzelnen Wörter zerlegt. Ein
Aufruf der Methode getNextToken liefert immer das jeweils nächste Wort,
solange hasMoreToken wahr zurückliefert.
Seite 8
Gruppe 18
Example 1
Modul Testprogramm
5
Modul Testprogramm
5.1
Beschreibung
Das Testprogramm stellt Befehle zur Verfügung mit der ein Graph bearbeitet
werden kann. Dazu wird zunächst ein leerer Testgraph erstellt. Es wird eine
Eingabeauforderung angezeigt, in der der Benutzer eine Reihe von durch das
Modul Input-Handler definierte Befehle zur Manipulation eines Graphen
eingeben kann.
Das Testprogramm ist dafür verantwortlich das alle vom Graphen und vom
Input-Handler
weitergereichte
Exceptions
durch
ihre
entsprechende
Fehlermeldungen dargestellt werden.
Das Testprogramm besteht lediglich aus der Klasse TestProgram und wird über
die Methode run vom Hauptprogramm aus gestartet.
5.2
Testfälle
Um das Programm automatisch auf Fehler zu überprüfen, wird eine Liste von
Befehlen in einer Datei bereitgestellt. Diese können dann einfach mittels
workflow < testinput.txt
in das Programm eingelesen und verarbeitet werden. Danach lässt sich die
Ausgabe mit einer zuvor händisch erstellten Referenz-Ausgabe vergleichen. Die
erledigt zum Beispiel das Programm diff und kann somit bequem zB in das
Makefile eingebaut werden.
Verschieden Testfälle werden mit anderen Gruppen gemeinsam erarbeitet und
ausgetauscht.
Gruppe 18
Seite 9
Herunterladen