UML
Die Unified Modeling Language, kurz UML, ist eine von der Object Management Group (OMG) entwickelte und standardisierte Sprache für die Modellierung von Software und anderen Systemen. Sie ist grafisch angelegt und arbeitet mit verschiedensten Diagrammen und einer (bis auf wenige Ausnahmen) fest definierten Semantik.
Sinn und Zweck
Der Entwicklungsprozess besteht aus vielen Schritten zwischen denen immer wieder sichergestellt werden muss, dass das produzierte Modell auch tatsaechlich der Spezifikation entspricht. UML stellt dabei eine Bruecke zwischen der Spezifikation auf der einen Seite und dem Code auf der anderen Seite dar. Es wird eine gemeinsame Kommunikationsplattform geschaffen auf deren Basis dann Entscheidungen bezueglich der Architektur getroffen werden koennen.
Fuer das Software Praktikum ist in erster Linie einmal das Klassendiagramm als Hauptstrukturgeber von Interesse. Am Klassendiagramm kann die Architektur leichter eroertert werden und es wird sowohl fuer die Tutoren als auch fuer die Studenten mehr Uebersicht geschaffen. Man hat sozusagen "etwas in der Hand" ueber das gesprochen werden kann und Fortschritte koennen auf diese Art kontinuierlich sichtbar gemacht werden. Es wird dafuer kein vollstaendig ausformuliertes Diagramm erwartet, auf Funktions- und Feldbeschreibungen kann in den meisten Faellen z.B. verzichtet werden. Die Klassenstrukturen und Navigationsmoeglichkeiten innerhalb derselben sollten allerdings schon deutlich gemacht werden.
Sichtweisen
UML as sketch
Hier steht der Aspekt einer gemeinsamen Sprache fuer die Kommunikation innerhalb des Entwicklerteams und mit den Auftraggebern im Vordergrund. Die UML Modelle werden hierbei nur so genau formuliert wie es die Kommunikation erfordert.
UML as blueprint
Bei dieser Anwendung von UML werden die UML Modelle direkt als Grundlage des Entwicklungsprozesses angesehen und muessen daher ausreichend spezifiziert sein um den Entwicklern eine genaue Umsetzung zu ermoeglichen. Die Struktur des Modells sollte vollstaendig Formal spezifiziert sein, waehrend das Verhalten durch textuelle Annotationen beschrieben werden kann. Diese Modelle koennen auch als Eingabe fuer Codegeneratoren verwendet werden, der entstandene Code muss jedoch anschliessend noch von Hand ueberarbeitet werden.
UML as programming language
Diese Nutzung erfordert vollkommen auspezifizierte UML Modelle was sowohl Struktur als auch Verhalten angeht. Bei diesem Ansatz ist es Ziel die Modelle ausfuehrbar zu machen und somit als Eingabe fuer Codegeneratoren zu benutzen die dann wiederum vollstaendige Programme generieren.
Das Klassendiagramm
Das Klassendiagramm ist eine Darstellung der Modellstruktur auf grafischer Ebene mit den von UML zur Verfuegung gestellten Mitteln. Formell gesehen ist ein Klassendiagramm ein gemischt gerichteter und ungerichteter Graph deren Knoten Klassen und deren Kanten Beziehungen zwischen diesen Klassen beschreiben.
Die Klassen
Syntax der Klassen
<graphviz> digraph KlasseUnbestimmt {
fontname = "Bitstream Vera Sans" fontsize = 8
node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ]
edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ]
Klasse [ label = "{Paket::Klasse| attribut, ...\l| operation(), ...\l}" ]
} </graphviz>
Beispielklasse
<graphviz> digraph KlasseBestimmt {
fontname = "Bitstream Vera Sans" fontsize = 8
node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ]
edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ] AutoKlasse [ label = "{DB::Auto| color : int\lspeed : float\l| accelerate(int speed) : void\lbreak() : bool\l}" ]
} </graphviz>
Abstrakte Klassen
Bei Abstrakten Klassen wird der Klassenname einfach Kursiv geschrieben. <graphviz> digraph KlasseAbstrakt {
node [ fontsize = 8 shape = "record" ]
edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ] AutoKlasse [
fontname = "Bitstream Vera Italic"
label = "{Auto| \l| \l}" ]
FordKlasse [ fontname = "Bitstream Vera Sans"
label = "{Ford| \l| \l}" ]
BMWKlasse [ fontname = "Bitstream Vera Sans"
label = "{BMW| \l| \l}" ]
edge [
arrowhead = "empty" ]
FordKlasse -> AutoKlasse BMWKlasse -> AutoKlasse
} </graphviz>
Schnittstellen
Schnittstellen (Interfaces) koennen folgendermassen dargestellt werden: <graphviz> digraph InterfaceDiagramm {
node [
fontname = "Bitstream Vera Sans"
fontsize = 8 shape = "record" ]
edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ] IFahrzeug [
label = "{\<\<interface\>\>\lIFahrzeug| \l| \l}" ]
AutoKlasse [
label = "{Auto| \l| \l}" ]
edge [ style = "dashed"
arrowhead = "empty" ]
AutoKlasse -> IFahrzeug
} </graphviz>
In diesem Fall wuerde die Auto Klasse also das Interface IFahrzeug implementieren.
Attribute
Attribute sind Felder in den Klassen die (i.d.R.) sowohl gelesen als auch geschrieben werden koennen.
Syntax für Attribute:
{Sichtbarkeit} Attributname : Typ
Operationen
Operationen sind als die Methoden einer Klasse zu verstehen und sind ausfuehrbar.
Syntax für Operationen:
{Sichtbarkeit} Operationsname (Parameterliste) : Rückgabetyp
Die Beziehungen
Generalisierung
Die Generalisierung stellt die klassiche Vererbungsrelation zwischen zwei Klassen her. Es handelt sich hierbei um eine "is a" Beziehung wie es sie auch bei semantischen Netzwerken gibt. Eine Generalisierung gebraucht man immer dann, wenn man von einer generelleren Klasse eine speziellere ableiten moechte. Diese speziellere Klasse erbt dann alle Merkmale (Attribute & Operationen) der Superklasse. Im folgenden Beispiel ist also Animal die Superklasse von Horse und Cat.
<graphviz> digraph Vererbung { rankdir = BT
node [ fontname = "Bitstream Vera Sans" fontsize = 8 shape = "record" ]
edge [ fontname = "Bitstream Vera Sans" fontsize = 8 ]
Animal [ label = "{Animal||\l}" ]
Horse [ label = "{Horse||\l}" ]
Cat [ label = "{Cat||\l}" ]
edge [ arrowhead = "empty" ]
Horse -> Animal Cat -> Animal
} </graphviz>
Assoziation
Assoziationen modellieren Beziehungen zwischen zwei oder mehr Klassen und koennen mit Multiplizitäten am jeweiligen Ende der Assoziation versehen werden um klarzumachen, wieviele Objekte in Relation zu den anderen Objekten stehen. Im folgenden Beispiel sagen die Multiplizitäten, dass jedem Fahrer beliebig viele Autos zugeordnet sein können, mindestens jedoch eines und ausserdem, dass jedes Auto entweder keinen oder genau einen Fahrer hat.
<graphviz> digraph Association { edge [ fontname = "Bitstream Vera Sans" fontsize = 8
]
node [ fontname = "Bitstream Vera Sans"
fontsize = 8
shape = "record" ]
Auto [ label = "{Auto||\l}" ]
Fahrer [
label = "{Fahrer||\l}" ]
Auto -> Fahrer [ arrowhead = "none" arrowtail = "none" headlabel = " 0..1" taillabel = "1..* " ]
} </graphviz>
Fuer die einfache Umsetzung in Konzepte von Objektorientierten Programmiersprachen empfiehlt es sich nur auf die Standard Multiplizitaeten "0..1" und "0..*" zurueckzugreifen. Im Regelfall werden diese Beziehungen durch Felder in den Klassen realisiert, bei "0..1" hat man genau diesen Fall, ein Feld kann entweder einen Wert haben oder nicht. Der andere Fall, "0..*" kann mit Collections abgedeckt werden, also z.B. Listen oder anderen flexiblen Datenstrukturen die dann als Feldtyp verwendet werden.
Navigierbarkeit ist ein wichtiges Konzept der Objektorientierten Programmierung, hierbei geht es um die Frage, welche Klassen von einer anderen Klasse aus erreichbar sind. D.h. dass eine Klasse A von der aus zu einer Klasse B navigiert werden können soll entsprechende Vorkehrungen treffen muss um dies möglich zu machen. Ein einfacher Weg besteht darin eine entsprechende Referenz auf die Klasse B in der Klasse A abzulegen. UML erlaubt wiederum eine grafische Repräsentation dieses Konzepts. Die jeweiligen Enden einer Assoziation können mit Symbolen versehen werden, die Aussagen über die Navigierbarkeit der Klassen machen:
<graphviz> digraph Navigation { edge [ fontname = "Bitstream Vera Sans" fontsize = 12
]
node [ fontname = "Bitstream Vera Sans"
fontsize = 8
shape = "record" ]
Auto_N [ label = "{Auto||\l}" ]
Fahrer_N [
label = "{Fahrer||\l}" ]
Auto_N -> Fahrer_N [ arrowhead = "none" arrowtail = "none" ] Auto_A [ label = "{Auto||\l}" ]
Fahrer_A [
label = "{Fahrer||\l}" ]
Auto_A -> Fahrer_A [ arrowhead = "vee" arrowtail = "none" ] Auto [ label = "{Auto||\l}" ]
Fahrer [
label = "{Fahrer||\l}" ]
Auto -> Fahrer [ arrowhead = "none" arrowtail = "none" headlabel = "X " ]
} </graphviz>
Von Links nach Rechts haben wir im obigen Beispiel folgende drei Fälle:
- Keine Aussage über die Navigierbarkeit
- Navigieren vom Auto zum Fahrer möglich
- Navigieren vom Auto zum Fahrer nicht möglich
Links
Bücher
- Heide Balzert: "Lehrbuch der Objektmodellierung – Analyse und Entwurf mit der UML 2" Elsevier Spektrum Akademischer Verlag, 2005, ISBN 3-8274-1162-9
- Heide Balzert: "UML 2 in 5 Tagen: Der schnelle Einstieg in die Objektorientierung" W3l Gmbh Verlag, 2008, ISBN 3868340025