Inhalt - Fakultät Informatik/Mathematik

Werbung
Sächs. VWA
Fritzsche: Software-Engineering
Inhalt
1
1.1
1.2
Ziele und Arbeitsmethoden der Softwaretechnologie
Methodologie der Softwareentwicklung
Die Modellierungssprache UML
2
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
Objektorientierte Modellierung
Klassen-Instanzen-Abstraktion
Attribute und Operationen
Sichtbarkeit und Lebensdauer
Assoziationen und Verknüpfungen
Aggregation und Komposition
Generalisierung und Spezialisierung
Vererbung und Delegation
Polymorphie
Abstrakte und konkrete Klassen
Instanzen als Laufzeitobjekte
Statechart-Modelle
Aktivitäts-Diagramme
3
3.1
3.2
3.3
3.4
3.5
Implementation von UML-Modellen
Von UML nach Java
Ein Beispiel: Baum-Klassen
Interfaces und Mehrfachvererbung
Implementation von Assoziationen und Aggregationen
Dynamische Modelle und Event-Handling
4
4.1
4.2
4.3
Systemarchitekturen
Komponentenmodelle
Verteilungsmodelle
Objektserialisierung
5
5.1
5.2
5.3
5.4
5.5
Der Softwareentwicklungsprozess
Anwendungsfall-Analyse
Methodische Aspekte der Modellierung
Qualitätssicherung
Projektmanagement und Prozessmodellierung
Konfigurationsmanagement
6
6.1
6.2
6.3
6.4
Wiederverwendung
Komponentenbasierte Softwareentwicklung - Frameworks
Entwurfsmuster
Grafische Benutzeroberflächen
Die Model-View-Controller-Architektur
1
Sächs. VWA
Fritzsche: Software-Engineering
Literatur
H. Balzert
Lehrbuch der Objektmodellierung. Analyse und Entwurf mit der UML 2.
Spektrum Akademischer Verlag, 2004
M. Fowler, K. Scott
UML konzentriert. Eine Einführung in die Standard-Objektmodellierungssprache.
Addison-Wesley, 2. Aufl. 2000
C. Rupp, S. Queins, B. Zengler
UML 2 glasklar, Praxiswissen für die UML-Modellierung
Carl Hanser Verlag, 3. Aufl., 2007
B. Oestereich
Objektorientierte Softwareentwicklung mit der Unified Modeling Language.
Oldenbourg, 3. Aufl., 1997
W. Pree
Komponentenbasierte Softwareentwicklung mit Frameworks.
dpunkt.verlag, 1997
I. Sommerville
Software Engineering
Pearson Studium - IT, 9. aktualisierte Auflage, 2012
Entwicklungsplattform Eclipse:
http://www.eclipse.org
Eclipse Dokumentation (Kepler release):
http://www.eclipse.org/kepler
Eclipse Dokumentation (Mars release):
http://www.eclipse.org/mars
Entwicklungsplattform Topcased:
http://topcased.org
2
Sächs. VWA
Fritzsche: Software-Engineering
3
1 Einführung: Ziele und Arbeitsmethoden der Softwaretechnologie
1.1
Methodologie der Softwareentwicklung
Die Softwaretechnologie (Software Engineering) ist die Lehre vom Prozess der organisierten Softwareproduktion. Sie umfasst (die Erforschung von) Theorie, Methoden und Werkzeuge(n) zur Herstellung von Software. Das schließt Maßnahmen zur
Qualitätssicherung, die Nachnutzung von Software sowie das Projektmanagement
und das Konfigurationsmanagement ein.
Dem Prozess der Softwareentwicklung wird im konkreten betrieblichen Umfeld jeweils ein Lebenszyklusmodell (auch als Vorgehensmodell bezeichnet) zugrunde gelegt. Bekannte Lebenszyklusmodelle sind u.a. das Wasserfallmodell und das Spiralmodell (letzteres ist ein evolutionäres Modell). Ein sehr einfaches Modell ist das
V-Modell. Für kleinere Entwicklergruppen ist die „Agile Softwareentwicklung“ ein bevorzugtes Modell.
Im Entwicklungsprozess lassen sich Entwicklungsphasen abgrenzen:
•
•
•
•
Analyse (Anforderungsanalyse (Pflichtenheft) – Anwendungsfallanalyse – Problembereichsanalyse) ,
Entwurf (Softwareentwurf – Algorithmenentwurf – Komponentenentwurf – Modelloptimierung) ,
Implementation (reduziert sich z.T. auf eine Generierung von Code bei Vorliegen formaler Spezifikationen) und
Test (Unit-Test, Integrationstest, Systemtest; teilweise auch entwicklungsbegleitend).
Es existiert nicht eine allgemein anerkannte Entwicklungsmethodik, sondern eine
Methodologie (d.h. Lehre von den Methoden ...) der Softwareentwicklung. Wichtige
Aspekte der Softwaretechnologie sind
-
1.2
die Entwicklung „großer“ Systeme (eine Entwicklergruppe arbeitet über längere Zeit an einem Vorhaben)
Rollenbindung beteiligter Personen
Erweiterung und Anpassung (Entwicklung endet nicht mit 1. Systemversion)
Wiederverwendung (Entwicklung beginnt nicht erst beim eigenen System)
Software-Architekturen (abhängig von eingesetzten Entwicklungsmethoden)
CASE (rechentechnische Unterstützung ist abhängig von angewandten Entwicklungsmethoden)
Zweckbindung führt auf Musterarchitekturen (z.B. Datenbank-Anwendungen)
Die Modellierungssprache UML
Die Unified Modeling Language (UML) ist eine grafische Modellierungs- und Entwurfssprache. Sie basiert auf Entwicklungen von G. Booch, J. Rumbaugh sowie I.
Jacobson und bildet seit Anfang der 1990er Jahre einen Quasi-Standard im Software Engineering. Mit der UML (aktuell: UML 2) werden Modelle entwickelt, die Ausschnitte einer zu modellierenden realen oder erdachten Welt widerspiegeln. Zur
Darstellung der Modelle unterschiedlicher Art dienen jeweils Diagramme. Diagramme visualisieren und formalisieren Ausschnitte aus bzw. Sichten auf Modelle.
Sächs. VWA
Fritzsche: Software-Engineering
Modelltypen:
•
•
•
•
•
•
Use-Case-Modell
Klassenstrukturmodell
Interaktionsmodell (Sequenz- u. Kommunikations-Diagramm)
Zustandsmodell (Zustands- u. Aktivitäten-Diagramm)
Komponentenmodell
Verteilungsmodell
Charakterisierung der grafischen Modellierungssprache: In der UML-Notation werden 4 Arten grafischer Konstrukte verwendet: Icons, 2-dimensionale Symbole, Pfade und Strings. Im Sinne eines Graphen bilden zweidimensionale Symbole Knoten,
die durch Pfade als Kanten verbunden sein können. Strings besitzen (mit Ausnahme
von Kommentaren) eine Syntax, sie können singulär auftreten oder anderen Sprachelementen zugeordnet sein.
Die UML ist eine (semi-)formale Sprache. Die Definition der Syntax (und evtl. der
Semantik) einer formalen Sprache erfolgt mit den Mitteln einer (formalen) Sprache.
Diese Sprache heißt Metasprache und dient zur Definition einer Objektsprache. Die
UML wird auch als Metasprache zur Modellierung von UML-Konzepten selbst eingesetzt (sog. Metamodellierung).
2 Objektorientierte Modellierung
2.1 Klassen-Instanzen-Abstraktion
Ein Objekt ist ein (abstrakter) Gegenstand oder ein Konzept mit klarer Abgrenzung
und präziser Bedeutung.
Beispiele: Kommissar Rex, das Fenster im Haus oben links, Herr Lutze, Mediatec
GmbH, ...
Eine Klasse beschreibt eine Menge von gleichartigen Objekten, die
•
•
•
ähnliche Struktur und ähnliche Merkmale (Attribute) besitzen,
ähnliches Verhalten zeigen (Operationen bzw. „Methoden“),
in Relationen zu Objekten anderer Klassen oder der gleichen Klasse stehen.
Eine Klasse kann durch Aufzählung aller zugehörigen Objekte oder durch die Definition der Eigenschaften der Objekte (Klassendefinition) beschrieben werden. Zu einer Klasse gehörige Objekte werden alternativ auch als Instanzen, Instanzobjekte
oder Exemplare der Klasse bezeichnet. Klassen werden benannt, besitzen also
einen Namen.
Beispiele: Hund, Fenster, Person, Firma, ...
Objekte bilden bei der Realisierung auf einem Rechner Implementierungseinheiten.
Objekte sind immer Instanzen einer bestimmten Klasse und besitzen eine Identität
und eine Lebensdauer. Jedes Objekt kennt die Klasse, zu der es gehört (Instanzierungsrelation). Eine Klassendefinition umfasst (evtl. implizit) die Beschreibung von
Vorschriften zur Erzeugung von Instanzen. Klassenbildung ist immer Abstraktion.
Bei einer Abstraktion werden für den Zweck der Betrachtung unwesentliche Eigenschaften weggelassen; sprich: „es wird von unwesentlichen Eigenschaften abstrahiert“. Abstraktion ist in der Informatik ein mächtiges Mittel zur Bewältigung von
Komplexität.
4
Sächs. VWA
Fritzsche: Software-Engineering
2.2 Attribute und Operationen
Attribute beschreiben die betrachteten strukturellen Merkmale, die alle zu einer
Klasse gehörenden Instanzen in einer gewissen spezifischen Ausprägung besitzen.
In einer Klassendefinition sind diese Attribute benannt. Jedes einzelne Objekt der
Klasse besitzt für jedes Attribut (Merkmal) eine individuelle Ausprägung (Merke: Objekt - Merkmal -Ausprägung, also „OMA“), die sich allerdings bei einem Objekt im
Laufe der Zeit ändern kann. „Ausprägungen“ sind Datenwerte eines in einer Klassendefinition vorbestimmten Datentyps. Der Wertebereich ist für jedes Attribut
(eventuell impliziert) in der Klassendefinition durch Angabe eines Typnamens festgelegt.
Jedes existierende Objekt einer Klasse besitzt für jedes Attribut zu einem bestimmten Zeitpunkt einen Wert aus dem Wertebereich. Der Wert für ein bestimmtes Attribut für ein Objekte kann von den bei anderen Objekten zum selben Zeitpunkt geltenden Werten verschieden sein.
Die Gesamtheit der Werte (d.h. der Ausprägungen) aller Attribute eines Objektes zu
einem bestimmten Zeitpunkt bildet den Zustand dieses Objektes.
Operationen definieren das Verhalten von Objekten. Alle Instanzobjekte einer Klasse verhalten sich in einer gewissen Weise gleichartig. Das Verhalten eines Objektes
wird dabei von den individuellen Ausprägungen der Attribute mitbestimmt. Die Verhaltensbeschreibung wird der Klassendefinition zugeordnet, und nicht jedem Objekt
einzeln. Sie existiert damit einmal unabhängig von der Anzahl vorhandener Instanzen, was bei der Implementation von Operationen in einer objektorientierten Programmiersprache genauso umgesetzt wird. Als „Methode“ bezeichnet man die Implementation einer Operation für eine Klasse. Eine Methode kann jeweils auf ein Instanzobjekt angewendet werden.
Eine spezielle Art der für eine Klasse definierbaren Operationen sind Konstruktoren.
Ein Konstruktor dient zur Erzeugung von Instanzobjekten, er wird also nicht auf ein
bereits bestehendes Instanzobjekt angewendet.
Eine Klasse wird in der UML durch ein Rechteck mit maximal drei Feldern für den
Klassennamen, die Attribute und die Operationen dargestellt. Klassennamen sollen
fett gedruckt sein und mit Großbuchstaben beginnen, die Namen von Attributen und
Operationen beginnen mit Kleinbuchstaben.
Instanzobjekte werden ebenfalls als Rechtecke mit maximal zwei Feldern dargestellt. Instanzobjekte können einen Namen besitzen oder auch unbenannt sein. Im
obersten Feld wird – wenn vorhanden - der Instanzname gefolgt von Doppelpunkt,
gefolgt vom Klassennamen angegeben. In jedem Fall wird aber ein Doppelpunkt
und nachfolgend der Klassenname angegeben.
Klassen können in einem Klassenstruktur-Diagramm dargestellt werden. Objektstrukturen können in Objektdiagrammen dargestellt werden. Ein Objektdiagramm
stellt eine „Momentaufnahme“ zur Laufzeit eines Systems dar.
In einigen Softwareentwicklungsumgebungen können Objekte und Klassen gemeinsam in einem Diagramm dargestellt werden. Eine gestrichelte Linie mit Pfeil zur
Klasse symbolisiert in diesem Fall die Beziehung zwischen Instanz und Klasse.
Notation einer Klasse:
5
Sächs. VWA
Fritzsche: Software-Engineering
6
klassenname
[visibility] attributname : typname [= default-wert]
…
…
[visibility] operationsname ( argumentliste) : ergebnistypname
…
…
Notation einer Instanz:
[instanznname] : klassenname
attributname = wert
…
…
Beispiel mit Angabe der Instanzierungsrelation:
Beachte: 'max' in 'max:Person' benennt das Objekt. Diese Benennung ist vom Namen bzw. dem Vornamen einer modellierten Person zu unterscheiden. Das Objekt
könnte auch mit 'p1' benannt sein, dann wäre p1:Person anzugeben.
2.3 Sichtbarkeit und Lebensdauer
Benennungen ordnen Klassen, Objekten, Attributen und Operationen Namen zu.
Namen sind immer innerhalb einer gewissen Umgebung (Environment) sichtbar,
d.h. unter Verwendung der Namen können die jeweiligen Dinge angesprochen werden. Außerhalb der Umgebung sind die entsprechenden Dinge nicht ansprechbar,
d.h. nicht referenzierbar. Es werden vier relative Sichtbarkeitsbereiche (sog. Visibility) abgegrenzt:
+
#
~
public
private
protected
package wide (Packages werden weiter unten beschrieben)
Sächs. VWA
Fritzsche: Software-Engineering
Objekte werden immer mittels Konstruktoren erzeugt. Objekte existieren solange,
solange sie referenzierbar sind oder bis sie explizit aus der Objektwelt entfernt werden.
Attribute können auf Instanzobjekte (instance scope) oder auf Klassen (class scope)
bezogen sein. Im Falle des Bezuges auf Klassen spricht man auch von „Klassenvariablen“.
Operationen können auf Instanzobjekte (instance scope) oder auf Klassen (class
scope) angewendet werden. Im Falle der Anwendung auf Klassen spricht man auch
von „Klassen-Methoden“.
2.4 Assoziationen und Verknüpfungen
Eine Assoziation ist eine abstrakte, d.h. nicht näher charakterisierte Beziehung zwischen zwei (binäre A.) oder mehreren Klassen. In der grafischen Darstellung werden die Symbole der beteiligten Klassen durch eine durchgezogene Linie verbunden. Die Enden einer Assoziationslinie können auch mit demselben Klassensymbol
verbunden sein.
Assoziationen höherer Ordnung (ternäre, ...) werden durch einen Rhombus dargestellt, der durch Linien mit den Symbolen der beteiligten Klassen verbunden ist. Assoziationen höherer Ordnung sollten praktisch nach Möglichkeit vermieden werden.
Sie sind schwerer zu verstehen, darzustellen und zu implementieren als binäre Assoziationen. Einer Assoziation kann im Klassenstrukturdiagramm ein Name oder sogar eine Klasse zugeordnet sein. Weitere Eigenschaften können durch Constraints
ausgedrückt werden.
Eine Verknüpfung (Link) ist ein Element einer Assoziation. Sie wird im Objektdiagramm dargestellt und setzt eine Anzahl von Objekten entsprechend der Ordnung
der Assoziation in Beziehung. Ist durch eine binäre Assoziation eine Klasse mit sich
selbst verbunden, können unterschiedliche Objekte dieser Klasse miteinander verknüpft sein oder ein Objekt mit sich selbst.
Beispiele:
7
Sächs. VWA
Fritzsche: Software-Engineering
In einer Assoziation können die beteiligten Klassen Rollen spielen. An den Enden
des die Assoziation kennzeichnenden Pfades können jeweils der Rollenname der
Klasse und eine Kardinalität notiert werden.
Durch die Angabe einer Kardinalität wird die Multiplizität beschrieben. Die Angabe
erfolgt durch die Aufzählung von Bereichen, die durch Komma getrennt werden.
Eine Bereichsangabe hat die allgemeine Form
untere-grenze .. obere-grenze. Ein * kann für eine nicht negative ganze Zahl zur
Kennzeichnung einer nach oben offenen Grenze gesetzt werden.
2.5 Aggregation und Komposition
Eine Aggregation ist eine Sonderform der Assoziation mit zusätzlicher Semantik und
bedeutet eine „Teil-Ganzes“-Beziehung. Objekte, die Komponenten einer Sache repräsentieren, sind mit einem Objekt verknüpft, das die Komponentengruppe (das
Aggregat) repräsentiert. Aggregation ist über eine beliebige Anzahl von Ebenen hinweg möglich.
Darstellung: hohle Raute an dem Ende der Assoziation, das dem Aggregat zugeordnet ist.
8
Sächs. VWA
Fritzsche: Software-Engineering
Ein Objekt der Klasse mit dem Namen Class1 repräsentiert die Komponentengruppe, Objekte der Klasse Class2 repräsentieren die Komponenten. Eine Komponentengruppe mit Komponenten verschiedener Typen hat entsprechend viele Aggregationen.
Eine Aggregation ist transitiv und antisymmetrisch.
Die Komposition wird als "enge" Aggregation verstanden, die eine Verbindung der
Teile mit dem Ganzen auch hinsichtlich der Lebenslinie bedeutet. Attribute einer
Klasse können als Komposition zwischen der Klasse und den Klassen (bzw. Typen)
der Attribute verstanden werden.
Darstellung: Ausgefüllte Raute anstelle der hohlen Raute.
Beispiele:
Ein Dokument besteht aus einer Anzahl von Absätzen, die ihrerseits aus mindestens einem Satz bestehen.
Ein Polygon besitzt mindestens drei Eckpunkte. Die Farbe und andere Eigenschaften (die Textur) sind dem Polygon fest zugeordnet und existieren nicht
ohne das Polygon. Ein Punkt existiert auch unabhängig vom Polygon, er kann
z.B. mehreren Polygonen gleichzeitig zugeordnet sein.
2.6 Generalisierung und Spezialisierung
Generalisierung und Spezialisierung sind Vorgänge, die eine Inklusions-Relation
zwischen (mindestens) einer allgemeineren und (mindestens) einer spezielleren Entität etablieren. Eine speziellere Entität besitzt alle Eigenschaften der allgemeineren
Entität (Inklusion) sowie zusätzliche und/oder anders ausgeprägte Eigenschaften
(sog. „is a“-Relation, deutsch etwa „ist eine Art von“).
Generalisierung und Spezialisierung werden zunächst auf Klassen angewendet.
Die Inklusionsrelation ist gerichtet. Sie ist transitiv und antisymmetrisch. Eine an der
Relation beteiligte allgemeinere Klasse wird als Superklasse (Oberklasse), eine speziellere Klasse als Subklasse (Unterklasse) bezeichnet.
Sprechweise: Ein Hund "ist eine Art von" (is-a) Säugetier.
9
Sächs. VWA
Fritzsche: Software-Engineering
10
Die Klasse Hund ist Subklasse zur Klasse Säugetier.
Ein Student "ist ein(e)" Person.
Die Klasse Person ist Superklasse zur Klasse Student.
Eine Subklasse hat gegenüber der zugeordneten Superklasse veränderte Eigenschaften. Dabei kann es sich um
-
zusätzliche Attribute,
zusätzliche Operationen,
Modifikationen bzw. spezielle Ausprägungen von Operationen,
Modifikationen von Festlegungen für Anfangswerte von Attributen
bzgl. der Instanzierung
handeln.
Durch Generalisierung bzw. Spezialisierung entstehen bzgl. der Inklusionsrelation
zyklenfreie, gerichtete Graphen.
In einer Klassenhierarchie kann eine Klasse nur eine Superklasse haben. In einer
Klassenheterarchie kann eine Klasse mehrere Superklassen haben. Eine Klasse mit
mehr als einer Superklasse heißt Vereinigungsklasse.
Grafische Notation:
Class3
Class4
Class5
Die Spitze des Dreiecks zeigt zur Superklasse.
Constraints
Für eine Generalisierung können Constraints angegeben werden (neben dem Dreieck in geschweiften Klammern notiert). Vordefinierte alternativ verwendbare Angaben sind overlapping vs. disjoint sowie complete vs. incomplete.
Sind alle Subklassen angegeben (die Anordnung ist vollständig, es werden keine
weiteren Subklassen erwartet) wird complete angegeben, andernfalls incomplete. Der implizit angenommene Standardwert (d.h. falls die Angabe fehlt) ist incomplete.
Kann ein Nachkomme von mehr als einer Subklasse abgeleitet werden, kann dies
durch overlapping gekennzeichnet werden. Das Gegenteil kann durch disjoint gekennzeichnet werden.
Beispiel:
Fahrzeuge können sowohl nach der Antriebsart (motorgetrieben, windgetrieben) als
auch nach dem Medium, auf bzw. in dem sie sich bewegen (Luft, Wasser, Land),
Sächs. VWA
Fritzsche: Software-Engineering
spezialisiert werden (vgl. Abbildung Abschnitt 3.3). Ein Lastkraftwagen (LKW) ist
demnach ein Fahrzeug, das motorgetrieben ist und sich auf dem Land bewegt.
2.7 Vererbung und Delegation
Als Vererbung (inheritance) wird die Weitergabe von Eigenschaften (Attribute, Operationen, Standardinitialwerte) einer Klasse an die Subklassen bezeichnet. Die Beschreibungen von Eigenschaften der Instanzen der Klasse werden entlang der Inklusionsrelation (an die Subklassen) vererbt. Tatsächlich müssen bei einer Klasse
die Eigenschaften ihrer Superklasse(n) nicht noch einmal beschrieben werden, sie
gelten implizit. Von besonderem Interesse ist, dass das auch bzgl. der Implementation gilt.
Durch Mehrfachvererbung ist es möglich, dass eine Klasse, die mehrere Oberklassen hat, Merkmale von allen Oberklassen erbt. Ein Merkmal aus der gleichen Vorfahrenklasse, das in mehr als einem Pfad gefunden wird, wird nur einmal geerbt, es
handelt sich um das gleiche Merkmal. Konflikte zwischen parallelen Definitionen
führen zu Mehrdeutigkeiten, die bei der programmtechnischen Realisierung gelöst
werden müssen.
Delegation ist ein Implementierungsmechanismus, mit dessen Hilfe ein Objekt eine
Operation auffängt und an ein anderes Objekt zur Ausführung sendet.
Zum Beispiel hat eine Klasse A ein Attribut, dessen Wertebereich die Instanzen einer Klasse B umfasst. Ein Instanzobjekt der Klasse A verwaltet (eine Referenz auf)
ein Objekt der Klasse B. Eine auf ein Objekt von A angewendete Methode kann damit ihrerseits (in ihrer Implementierung) eine entsprechende Methode auf das verwaltete Objekt von B anwenden. Operationen werden aber nicht automatisch über
die Aggregation hinweg vererbt!
Mittels Aggregation und Delegation kann fehlende Mehrfachvererbung umgangen
werden. Es bestehen folgende Möglichkeiten:

Delegation durch Verwendung von Rollenaggregation

Vererbung der wichtigsten Klasse und Delegation des Restes

Verschachtelte Generalisierung
2.8 Polymorphie
Polymorphie bedeutet Vielgestaltigkeit. Der Begriff wird hier verwendet, um hervorzuheben, dass mit demselben Namen zu unterschiedlichen Zeitpunkten unterschiedliche Methoden (d.h. unterschiedliche Implementationen von Operationen)
benannt werden können.
Beispiel:
Wir betrachten Unruhen (mobiles) und möchten mit einer Operation balancedp()
bestimmen, ob sich eine Unruhe im Gleichgewicht befindet. Abstrahiert man von
den physikalischen Gegebenheiten, handelt es sich bei den Unruhen um eine spezielle Art gewichtsbalancierter Bäume (im Unterschied zu höhenbalancierten Bäumen). Wir modellieren eine Klasse Mobile mit den Attributen "linker Nachfolger"
(lsucc) und "rechter Nachfolger" (rsucc). Die Attribute sind vom Typ Mobile, d.h.
entsprechende Attribute können Referenzen auf Objekte vom Typ Mobile aufnehmen. Die Armlängen (links bzw. rechts von der Aufhängung) spielen zunächst keine
Rolle. Es wird angenommen, sie sind für jede Unruhe links und rechts gleich groß.
11
Sächs. VWA
Fritzsche: Software-Engineering
Jede Unruhe verwaltet ein Objekt vom Typ Node. Das Attribut key der Klasse Node
ist vom Typ int (ganze Zahl) und dient zur Identifikation einer Unruhe. Nur für Unruhen ohne Nachfolger (d.h. für Blattkelemente im Baum der Unruhen) enthält das
Attribut key das Gewicht. Bei Unruhen mit Nachfolgern (inneren Knoten) wird key
der Wert 0 zugewiesen. Wird die Operation weight auf ein Objekt vom Typ Mobile angewendet, liefert sie bei Blattelementen den Wert von key und sonst die
Summe der Gewichte der Nachfolgerknoten.
Die Klasse MobileA spezialisiert die Klasse Mobile in der Weise, dass die Arme
einer Unruhe unterschiedlich lang sein können. Zur Speicherung der Armlängen dienen die Attribute larm und rarm. Die Attribute lsucc und rsucc werden von Mobile an MobileA vererbt. Die Methode balancedp() kann sowohl auf Instanzen
von Mobile als auch von MobileA angewendet werden. Für jeden dieser Fälle
wird in Abhängigkeit vom Typ des aktuellen Objekts allerdings eine andere Methode
ausgeführt. Da in diesem Fall zur Laufzeit entschieden wird, welche Methode tatsächlich ausgeführt wird, heißt diese Art der Polymorphie "dynamische Polymorphie". Bezogen auf die Implementation spricht man von „später Bindung“ oder auch
„dynamischer Bindung“.
Die öffentlichen Methoden insKeyWeight, insLsucc, insRsucc, insLarm und
insRarm dienen der Konstruktion von Unruhen.
2.9 Abstrakte und konkrete Klassen
Eine abstrakte Klasse ist eine Klasse, die selbst keine direkten Instanzen besitzt.
Eine abstrakte Klasse wird modelliert mit der Absicht, Subklassen zu schaffen, die
Merkmale und Verhalten hinzufügen bzw. konkretisieren. Zu den als Nachkommen
geschaffenen Klassen werden dann Instanzen gebildet.
Eine konkrete Klasse ist eine Klasse, die direkte Instanzen besitzen kann ("instanziierbare Klasse").
Nur konkrete Klassen können Blattklassen im Vererbungsbaum sein!
Eine abstrakte Klasse kann sowohl abstrakte Operationen als auch nicht abstrakte
Operationen definieren.
12
Sächs. VWA
Fritzsche: Software-Engineering
Eine Operation kann abstrakt sein. Eine abstrakte Klasse definieret in diesem Fall
nur die Signatur einer Operation, ohne eine entsprechende Methode zu implementieren. Eine Kennzeichnung im Klassensymbol erfolgt entweder durch den Zusatz
{abstract} oder dadurch, dass die Signatur der Operation in italics gesetzt wird.
Ein Auftreten der Signatur der Operation in einer abgeleiteten Klasse (ohne Kennzeichnung als abstrakte Operation) zeigt an, dass die abgeleitete Klasse eine Methode für die Operation definiert.
2.10 Instanzen als Laufzeitobjekte
Ein Objekt ist als Instanz einer Klasse ein Laufzeitobjekt. Es belegt bei der programmtechnischen Realisierung Speicherplatz, hat eine Identität und besitzt eine
gewisse Lebensdauer. Objekte können benannt werden. Das bedeutet, dass eine
Assoziation zwischen einem Namen (einem Bezeichner) und einer Objektreferenz
aufgebaut wird. Namen sind einem Sichtbarkeitsbereich (scope) zugeordnet.
Wir unterscheiden (vgl. Abschnitt 2.3):
- global
- Paket-lokal
- Klassen-lokal (evtl. inclusive Vererbung)
- Methoden-lokal
Im Laufe der Zeit können sich solche Assoziationen ändern, d.h. ein Name kann mit
einer Referenz auf ein anderes Objekt assoziiert werden.
Typkompatibilität bedeutet, dass einem Bezeichner, der mit einer Referenz auf ein
Objekt eines bestimmten Typs (z.B. einer Klasse) assoziiert ist, ein Objekt eines anderen Typs (einer anderen Klasse ("Referenzklasse")) zugeordnet werden kann. Typkompatibilität wird in UML nicht speziell unterstützt. Welche Typen kompatibel sind,
hängt bei der programmtechnischen Realisierung von der verwendeten objektorientierten Programmiersprache ab.
Die Erzeugung eines Objektes kann auf zweierlei Weise erfolgen:
1. statisch, mit der Initialisierung des Anwendungssystems (per „Compilezeit“) oder
2. dynamisch, durch Anwendung eines Konstruktors der entsprechenden
Klasse während der Ausführung einer Methode (per „Laufzeit“).
13
Sächs. VWA
Fritzsche: Software-Engineering
Objektzustände: vordefinierte Ausprägungen für Zustände von Objekten sind
•
•
•
•
•
nicht existent (eigentlich ein Widerspruch!)
existent: Für ein Objekt wurde Speicher erfolgreich angefordert, die
Zuordnung der Methoden aus der Klassendefinition war erfolgreich.
initialisiert
deinitialisiert
gelöscht
Für persistente Objekte werden zusätzliche Zustände erklärt: ausgelagert, im-Speicher. Ein ausgelagertes Objekt ist nicht im Adressraum des Arbeitsspeichers verfügbar, kann aber wieder in den Arbeitsspeicher geladen werden.
Das Erzeugen und Löschen von Objekten kann in Sequenzdiagrammen dargestellt
werden. In vielen objektorientierten Programmiersprachen kann der Zeitpunkt zum
Löschen eines Objektes vom Programmierer selbst geplant werden (z.B. C++).
Objekte können miteinander mittels Nachrichten kommunizieren (senden und empfangen). Ein Objekt kann seinen Zustand verändern infolge von Reaktionen auf
 Methodenaufrufe (method invocation)
 Ereignisse (events)
Ein Sequenzdiagramm zeigt das Verhalten von Objekten entlang einer Zeitachse
(„Lebenslinie“ des Objekts) und berücksichtigt dabei die Interaktion mit anderen Objekten durch den Austausch von Nachrichten. Mit Hilfe von Sequenzdiagrammen
werden Szenarios beschrieben.
Szenario: Folge von Ereignissen, die bei einer ganz bestimmten Ausführung eines
Systems auftritt. Es kann alle Ereignisse eines Systems betreffen oder Ereignisse,
die bestimmte Objekte eines Systems beeinflussen oder von bestimmten Objekten
erzeugt werden.
Ein Szenario erhält man durch Aufzeichnung bei der Ausführung eines Systems
oder durch gedankliche Vorausplanung der Aufzeichnung.
Im Sequenzdiagramm ist eine Aufteilung der Lebenslinie eines Objekts in parallele
Zweige möglich. Parallele Lebenslinien können an einem späteren Punkt wieder zusammengeführt werden.
14
Sächs. VWA
Fritzsche: Software-Engineering
Object1
15
Object2
1: nachricht()
1.1: antwort()
2.11 Statechart-Modelle
Ein Zustandsautomat (das ist ein endlicher Automat) ist ein Graph, bestehend aus
Zuständen und Transitionen, der die Reaktion eines Objektes einer Klasse auf den
Empfang von "äußeren Stimuli" beschreibt. Ein Zustandsautomat ist einer Klasse
oder einer Methode zugeordnet.
Ein Zustand (state) ist die Verfassung (im Verlaufe des Lebens) eines Objektes, in
der es einer Bedingung genügt, eine Aktion ausführt oder auf ein Ereignis wartet.
Ein Objekt verweilt eine endliche Zeit in einem Zustand.
Eine Transition ist eine durch ein Ereignis verursachte Zustandsänderung eines Objektes.
Notation:
event(argument ...) [ bedingung ]/ operation(argument ...)
Ereignisse (events) sind bemerkenswerte Vorkommnisse. In Bezug auf Statecharts
ist ein Ereignis ein Vorkommnis, das eine Transition auslöst. Es hat selbst keine
Dauer. Der Zustand eines Objekts bestimmt die Reaktion des Objekts auf ankommende Ereignisse. Reaktionen können Aktionen und/oder Zustandsänderungen
sein.
Aktionen (actions) sind atomar und nicht unterbrechbar. Ein Zustand kann mit einer
andauernden Aktivität verbunden sein. Eine solche Aktivität wird selbst als Zustandsautomat ausgedrückt. Eine andauernde Aktivität kann als Paar von Aktionen
ausgedrückt werden.
Notation: Ein Statechart (Zustands-Diagramm) repräsentiert einen Zustandsautomaten. Zustände werden durch Zustandsymbole (Rechteck mit abgerundeten
Ecken) repräsentiert. Sie können einen Namen beinhalten und optional durch horizontale Linien in bis zu drei Bereiche geteilt werden. Spezielle Symbole existieren
für den Startzustand und Endzustände:
Sächs. VWA
Fritzsche: Software-Engineering
16
Transitionen sind Zustandsübergänge und werden durch Pfeile dargestellt, die Zustandssymbole verbinden. Ereignisse, die Zustandsübergänge auslösen, werden als
Beschriftung an die zugehörigen Pfeile geschrieben.
Interpretation:
•
wenn sich ein Objekt in einem Zustand befindet, und ein Ereignis tritt auf, mit dem
eine seiner Transitionen beschriftet ist, geht das Objekt in den Zustand am Ende der
Transition über: Die Transition „feuert“.
•
wenn ein Ereignis auftritt, für das es keine vom aktuellen Zustand ausgehende Transition gibt, wird das Ereignis ignoriert.
Übergänge ohne Ereignisbeschriftung werden automatisch ausgelöst, sobald die mit
dem Zustand verbundenen Aktionen/Aktivitäten abgeschlossen sind.
Ereignisse können mit Bedingungen verknüpft sein. Die an ein Ereignis geknüpften
Bedingungen müssen erfüllt sein, damit der erwartete Zustandswechsel erfolgen
kann.
Beispiel:
Zustände können auch Subdiagramme enthalten. Zustände können in
sequentielle
parallele
Unterzustände dekomponiert werden. Eine Verfeinerung ist jeweils nur auf einem
dieser beiden Wege möglich.
Sächs. VWA
Fritzsche: Software-Engineering
17
2.12 Aktivitäts-Diagramme
Das Aktivitäts-Diagramm ist eine spezielle Art des Zustandsdiagramms, das ausschließlich Aktivitäten und Übergänge zwischen diesen zeigt. Eine Aktivität ist einem
Zustand zugeordnet und repräsentiert eine andauernde interne Aktion. Mehrere von
einer Aktivität ausgehende Transitionen werden durch Bedingungen unterschieden:
Activity3
[x > 0]
Activity1
Activity2
[x = 0]
[x < 0]
Activity4
Activity2
Activity3
[x = 0]
Activity4
[x > 0]
[x < 0]
Activity5
Start- und Endzustand werden wie im Zustandsdiagramm dargestellt.
Ereignisse werden nicht dargestellt. Transitionen können geteilt und synchronisiert
werden (Parallelität):
Activity1
Activity2
Activity4
Activity3
Sächs. VWA
Fritzsche: Software-Engineering
3 Implementation von UML-Modellen
3.1 Von UML nach Java
Applikationen und Applets
Eine Java-Applikation ist ein Programm in einer virtuellen Maschinensprache (Java
Virtual Machine Specification). Ein solches Programm wird interpretativ durch den
Java-Interpreter java verarbeitet. Um z.B. das Programm MyApplication abzuarbeiten, ist in der Kommandozeile einzugeben:
java MyApplication
Der Name des auszuführenden Programmes wird dem Interpreter java als Kommandozeilenparameter übergeben.
Durch diese Art der Verarbeitung wird Plattformunabhängigkeit gewährleistet, die
Verfügbarkeit eines Interpreters auf jeder Plattform vorausgesetzt. Java-Applikationen besitzen eine Klassenstruktur, d.h. sie bestehen aus einer Anzahl zusammenwirkender Klassen.
Ein Java-Programm in der virtuellen Maschinensprache liegt in einer Datei vor. Dateiextension ist .class. Eine .class-Datei wird durch den Java-Compiler aus einer gleichnamigen .java-Datei erzeugt, die den Programmtext enthält. Bei Aufruf
des Java-Interpreters wird die Dateiextension .class weggelassen. Im obigen Beispiel ist der vollständige Dateiname MyApplication.class.
Beispiel: Die Anwendung MyApplication besteht aus einer Klasse, der Hauptklasse MyApplication. Der Programmtext könnte wie folgt aussehen:
public class MyApplication {
public static void main (String args[]){
System.out.println("Kommandozeilenparameter:");
for (int i = args.length - 1; i>=0; i--)
System.out.println(args[i]);
}
}
Die Hauptklasse einer Anwendung (z.B. MyApplication) muß die Methode
main() implementieren. Mit static gekennzeichnete Methoden oder Variablen
beziehen sich auf eine Klasse (betrachtet als Objekt) und nicht auf ein Instanzobjekt
der Klasse. Wir nennen sie Klassenmethoden bzw. Klassenvariablen. Für jede Methode ist ein Ergebnistyp festzulegen. Wird dieser mit void angegeben, liefert die
Methode keinen Ergebniswert.
Beim Programmaufruf können Kommandozeilen-Parameter an eine Applikation
übergeben werden. Im Beispiel kann über das String-Array args in der main-Methode auf solche Parameter zugegriffen werden.
Zur Verwaltung seiner Länge (Anzahl seiner Elemente) besitzt jedes Array das Feld
length. Auf dieses Feld wird wie auf eine Instanzvariable eines Objektes zugegriffen.
Zeichenketten (Typ String) sind immer Objekte, also keine Character-Arrays. Die
Klasse String wird in einer Klassenbibliothek bereitgestellt. Bei der Erzeugung von
String-Objekten kann eine Initialisierung mittels String-Literalen vorgenommen werden:
String s = new String("Kommandozeilenparameter:")
18
Sächs. VWA
Fritzsche: Software-Engineering
int, float, char, boolean bezeichnen elementare Datentypen (keine Klassen).
Zu jedem elementaren Datentyp gibt es eine korrespondierende Klasse.
Java-Programme können auf die Standard-Ein-/Ausgabe zugreifen. System ist eine
abstrakte Klasse. System.in ist eine Variable für die Standard-Eingabe. Analog ist
System.out eine Variable für die Standard-Ausgabe.
Beispiel für einen Aufruf:
java MyApplication huhu haha hoho
Kommandozeilenparameter:
hoho
haha
huhu
Applets
Applets sind Java-Anwendungen, die in HTML-Dokumente mittels eines AppletTags eingebunden werden können. Die gängigen Browser verfügen über eine JVM
zur Interpretation solcher Java-Anwendungen.
Beispiel:
<html>
<head>
<title>Applet-Demonstration</title>
<!-- (c)Hartmut Fritzsche, 20-Sept-1998-->
</head>
<body background=back_ms.gif text=#0000cc>
<h1>Lehrveranstaltung "Software Engineering"</h1>
<applet
codebase="file:/home/fritzsch/java/SE_LV"
code="ChboxDemo.class"
alt="Applet!!!"
width=500 height=300 align=bottom>
The Browser doesn't know the applet-tag.
</applet>
</body>
</html>
Ein Browser, der das Applet-Tag nicht kennt, überliest es. Alternative HTML-Elemente können in die Applet-Umgebung eingefügt werden. Kennt ein Browser das
Applet-Tag im obigen Beispiel nicht, erscheint stattdessen The Browser doesn't
know the applet-tag. Das Attribut ALT wird verwendet, um bei Textbrowsern
anstelle des Applets alternativen Text zu zeigen. Mit dem Attribut CODE wird die Datei spezifiziert, in der die Hauptklasse des Applets liegt.
Jede Klasse, die ein Applet realisiert, muss von der Klasse Applet abgeleitet sein,
d.h. von dieser Klasse erben (extends …). Jedes Applet besitzt die Methoden
init(), start(), stop() und destroy(), die standardmäßig keinen Code enthalten. Die Methoden stehen im Zusammenhang mit dem Lebenszyklus eines Applets.
Beispiel:
import java.applet.Applet;
import java.awt.*;
19
Sächs. VWA
Fritzsche: Software-Engineering
public class AppletDemo extends Applet{
String text;
public void init(){
System.out.println("init");
if ((text = getParameter("text")) == null)
text = "kein text-Parameter vorhanden";
System.out.println(text);
}
}
public void start(){
System.out.println("start");
}
public void stop(){
System.out.println("stop");
}
public void destroy(){
System.out.println("destroy");
}
public void paint(Graphics g){
g.drawString("Hello world !",90,25);
}
Ein Browser gibt Ausgaben auf der Standardausgabe über die "Java-Console" aus.
Ist das Applet während der Präsentation geändert worden, d.h es ist ein neues
.class-File erzeugt worden, muss der Applet-Viewer neu gestartet werden, um
das geänderte Applet zu präsentieren.
3.2 Ein Beispiel: Baum-Klassen
Als Beispiel sollen die im Abschnitt über Polymorphie betrachteten und modellierten
Unruhen nun implementiert werden. Getreu dem Klassenmodell programmieren wir
die Klassen Mobile, MobileA und Node.
public class Mobile{
Node root = new Node();
Mobile lsucc,rsucc;
void insKeyWeight(int key,int weight){
node.setKey(key);
node.setWeight(weight);
}
void insLeft(Mobile s){
lsucc = s;
}
void insRight(Mobile s){
rsucc = s;
}
int weight(){
if (node.getWeight() == 0)
return( lsucc.weight() + rsucc.weight() );
else
return( node.getWeight());
20
Sächs. VWA
Fritzsche: Software-Engineering
}
boolean balancedp(){
if (node.getWeight() == 0)
return(
lsucc.balancedp()
&& rsucc.balancedp()
&& (lsucc.weight() == rsucc.weight()));
else
return(true);
}
void makebalance(){
}
}
class MobileA extends Mobile{
private int larm,rarm;
void setLarm(int a){
larm = a;
}
void setRarm(int a){
rarm = a;
}
boolean balancedp(){
if (node.selWeight() == 0)
return(
lsucc.balancedp()
&& rsucc.balancedp()
&& (larm * lsucc.weight()
== rarm * rsucc.weight()));
else
return(true);
}
public void makebalance(){
int s = larm + rarm;
if (root.selWeight() == 0){
((MobileA)lsucc).makebalance();
((MobileA)rsucc).makebalance();
if (!(this.balancedp())){
rarm = lsucc.weight()*s/this.weight();
larm = s - rarm;}
System.out.println(larm);
System.out.println(rarm);
}
}
}
class Node{
private int key,weight;
int getWeight(){
return weight;
}
int getKey(){
return key;
}
void setWeight(int weight){
this.weight = weight;
}
void setKey(int pkey){
key = pkey;
21
Sächs. VWA
Fritzsche: Software-Engineering
}
}
Die Klasse UseMobile bietet eine beispielhafte Anwendung:
public class UseMobile {
public static void main(String args[]){
System.out.println("Hello world!");
Mobile m1 = new Mobile();
m1.insKeyWeight(1,0);
Mobile m2 = new Mobile();
m2.insKeyWeight(2,4);
Mobile m3 = new Mobile();
m3.insKeyWeight(3,0);
Mobile m4 = new Mobile();
m4.insKeyWeight(4,0);
Mobile m5 = new Mobile();
m5.insKeyWeight(5,1);
Mobile m6 = new Mobile();
m6.insKeyWeight(6,1);
Mobile m7 = new Mobile();
m7.insKeyWeight(7,2);
m4.insLsucc(m5);m4.insRsucc(m6);
m3.insLsucc(m4);m3.insRsucc(m7);
m1.insLsucc(m2);m1.insRsucc(m3);
System.out.println(m1.weight());
System.out.println(m1.balancedp());
MobileA ma1 = new MobileA();
ma1.insKeyWeight(1,0);
MobileA ma2 = new MobileA();
ma2.insKeyWeight(2,3);
MobileA ma3 = new MobileA();
ma3.insKeyWeight(3,0);
MobileA ma4 = new MobileA();
ma4.insKeyWeight(4,0);
MobileA ma5 = new MobileA();
ma5.insKeyWeight(5,2);
MobileA ma6 = new MobileA();
ma6.insKeyWeight(6,1);
MobileA ma7 = new MobileA();
ma7.insKeyWeight(7,1);
ma4.insLeft(ma5);ma4.insRight(ma6);
22
Sächs. VWA
Fritzsche: Software-Engineering
ma4.insLarm(1);ma4.insRarm(2);
ma3.insLeft(ma4);ma3.insRight(ma7);
ma3.insLarm(1);ma3.insRarm(3);
ma1.insLeft(ma2);ma1.insRight(ma3);
ma1.insLarm(4);ma1.insRarm(3);
System.out.println(ma1.weight());
System.out.println(ma1.balancedp());
}
ma4.insLarm(4);
System.out.println(ma1.weight());
System.out.println(ma1.balancedp());
ma1.makebalance();
System.out.println(ma1.weight());
System.out.println(ma1.balancedp());
System.out.println("Bye world!");
}
Abarbeitung des (zuvor übersetzten) Programmes:
C:\WorkStation\SE>java UseMobile
Hello world!
8
true
7
true
7
false
2
4
1
3
4
3
7
true
Bye world!
3.3 Interfaces und Mehrfachvererbung
In Java gibt es (z.B. im Unterschied zu C++) keine Mehrfachvererbung. Statt dessen
gibt es sog. Interfaces, die aber reine Schnittstellen darstellen und keinerlei Implementierung enthalten. Interfaces definieren ausschließlich abstrakte Methoden und
Konstanten.
Eine Klasse kann ein oder mehrere Interfaces implementieren. Wenn eine Klasse
ein Interface implementiert, dann muss sie alle seine Methoden überschreiben. Die
Eigenschaft einer Klasse, ein Interface zu implementieren, wird an ihre Nachfahren
vererbt.
23
Sächs. VWA
Fritzsche: Software-Engineering
3.4 Implementation von Assoziationen und Aggregationen
Zur Implementation von Assoziationen und Aggregationen mit 1:n – Beziehungen
eignen sich Vektoren und Hash-Tabellen.
Ein Vektor ist in Java (als Instanz der Klasse Vector) ein eindimensionales dynamisches Array. „Dynamisch“ bedeutet hier, dass die Anzahl der Elemente zur Laufzeit des Programms vergrößert werden kann. Der Klass Vector zugeordnete Methoden sind addElement, insertElement, removeElement. Die Methode
size liefert als Wert die Anzahl der Elemente eines Vektors.
Hash-Tabellen bieten den statistisch gesehen schnellsten Zugriff auf Elemente einer
Elementsammlung und werden deshalb häufig eingesetzt. In ca. 70 – 90 % aller Fälle wird ein Direktzugriff möglich sein. In Java ist eine entsprechende Klasse
Hastable verfügbar.
3.5 Dynamische Modelle und Event-Handling
Ziel ist hier die Umsetzung von Zustandsdiagrammen in Java-Programme. Bei jeder
Mausbetätigung (auch Mausbewegung!) oder Tastatureingabe wird ein Objekt der
Klasse Event bzw. einer Subklasse dieser Klasse erzeugt. Den Programmkomponenten, die auf Events reagieren sollen, werden zur jeweiligen Event-Art passende
Listener hinzugefügt.
Die Programmierung der gewünschten Aktionen bei Eintreten bestimmter Ereignisse
erfolgt in sog. Handlern. Listener-Interfaces definieren solche Handler zur Behandlung von Events. Ein Listener kann mehrere Event-Quellen haben. Zu einer EventQuelle kann es andererseits auch mehrere Listener geben.
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
24
Sächs. VWA
Fritzsche: Software-Engineering
25
public class AcEvDemo2 extends Applet implements ActionListener {
public void init() {
System.out.println("Hello world!");
Button bopen = new Button("open");
Button bclose = new Button("close");
bopen.addActionListener(this);
bclose.addActionListener(this);
add(bopen);
add(bclose);
System.out.println("I am waiting for events.");
}
public void actionPerformed(ActionEvent evt) {
if (evt.getActionCommand().equals("open")){
System.out.println("action in open");
}
if (evt.getActionCommand().equals("close")){
System.out.println("action in close");
}
}
}
4 Systemarchitekturen
4.1 Komponentenmodelle
Betrachtet man die logische Struktur eines objektbasierten Systems, so sieht man
Klassenstrukturen. Bei der Systemarchitektur wird dagegen häufig eine nicht objektbasierte Komponentenstruktur zugrunde gelegt. Zur Darstellung der Komponentenstruktur werden Komponentenmodelle verwendet. Komponentenmodelle werden in
der UML mit Komponentendiagrammen repräsentiert. Eine Komponente stellt eine
physikalische Programmeinheit dar, die als Quellcode, Objektcode oder ausführbares Programm vorliegen kann. Komponenten werden in Subsystemen (Paketen) organisiert.
Pakete (packages) werden zur Gruppierung von Modellelementen verwendet.
In Java umfasst ein Paket eine beliebige Anzahl von Compilationseinheiten. Pakete
können hierarchisch gegliedert sein. Dabei korrespondieren Paketnamen mit
Pfad-/Dateinamen.
Darstellung :
Subsystem1
Component1
Component2
Sächs. VWA
Fritzsche: Software-Engineering
26
4.2 Verteilungsmodelle
Das Verteilungsdiagramm ermöglicht die Modellierung expliziter physischer Strukturen. Es enthält Knoten, auf denen Prozesse ablaufen. Knoten werden durch Quader
dargestellt.
Client1
Server1
Component1
Client2
Component2
4.3 Objektserialisierung
Die Objektserialisierung dient der persistenten Speicherung von Laufzeitobjekten einer Java-Applikation zu einem bestimmten Zeitpunkt. Das Speichern in eine Datei
wird als „Serialisieren“ bezeichnet. Im Paket java.io existiert eine Klasse ObjectOutputStream, auf die die Methode writeObject anzuwenden ist. Zu serialisierende Objekte sind dieser Methode als Parameter zu übergeben. Das Wiederherstellen einer Objektwelt durch Lesen aus der zuvor serialisierten Objektwelt wird als
„Deserialisieren“ bezeichnet. Dazu ist die Methode readObject der Klasse ObjectInputStream anzuwenden.
5 Der Softwareentwicklungsprozess
5.1 Anwendungsfall-Analyse
Ein Anwendungsfall (use case) beschreibt die Interaktionen zwischen Anwendern
und dem Anwendungssystem, die notwendig sind, um einen Arbeitsgang durchzuführen. Im Wesentlichen sind Anwendungsfälle und Akteure zu identifizieren. Das
Darstellungsmittel der UML für Anwendungsfälle sind UseCase-Diagramme. Ein
UseCase-Diagramm zeigt die Beziehungen zwischen Akteuren (actors) und Anwendungsfällen in einem System. Das System wird durch ein Rechteck dargestellt, das
die Systemgrenzen zeigt.
Im UseCase-Diagramm können auch Import-Beziehungen (<<include>>) und Erweiterungen (<<extend>>) zwischen Anwendungsfällen gezeigt werden. Auch Generalisierung/Spezialisierung zwischen Anwendungsfällen kann modelliert werden.
Sächs. VWA
Fritzsche: Software-Engineering
27
5.2 Methodische Aspekte der Modellierung
In der Analysephase sind folgende Aktivitäten erforderlich:
• Zerlegung des Anwendungsbereiches in Unterbereiche
• Analyse und Spezifikation des geforderten Systemverhaltens
Während der Problembereichsanalyse werden zunächst „Geschäftsklassen“ modelliert. „Fachklassen“ beschreiben im Unterschied dazu implementierungs-technische
Sachverhalte.
Zur Entwicklung eines Objektmodells wird von RUMBAUGH folgendes Vorgehen empfohlen:
1. Objektklassen identifizieren
2. ein Data Dictionary vorbereiten
3. Assoziationen zwischen Objektklassen identifizieren
4. Attribute identifizieren und zu Objektklassen hinzufügen (Operationen erst spät beim
Spezifizieren des Zustandsmodells hinzufügen)
5. Klassen mittels Vererbung organisieren
6. Zugriffspfade testen
7. das Gesamtmodell in einem iterativen Prozess verfeinern
8. Klassen zu Paketen (Teilsystemen) gruppieren
5.3 Qualitätssicherung
Die Qualitätssicherung umfasst Planung/Durchführung von Qualitätssicherungsmaßnahmen (QSM) , die Kontrolle der Einhaltung von Standards (ISO 9000, ... )
und die Qualitätsbewertung anhand von Metriken. Es werden konstruktive und analytische QSM unterschieden. Zu den analytischen QSM zählen statische Analysen,
Sächs. VWA
Fritzsche: Software-Engineering
der symbolische Test und dynamische Analysen (das „Testen“). Zu den statischen
Analysen zählen Kontrollfluss- und Datenflussanalyse sowie die Programmverifikation (Beweis der Korrektheit eines Programms mit mathematischen Mitteln).
5.4 Projektmanagement und Prozessmodellierung
Das Projektmanagement (PM) umfasst alle Maßnahmen zur Planung und Verfolgung einzelner Projekte und von Projektfamilien. Zur Projektplanung zählen:
• Festlegung der Projektorganisation
• Personalplanung
• Meilenstein-/Terminplanung für alle Aktivitäten und Zuordnung zu Bearbeitern.
Die Projektverfolgung umfasst alle technisch-organisatorischen Maßnahmen zur Erreichung der Projektziele. Dazu zählen die Verfolgung von Meilensteinen, Terminen
und (Rest-) Aufwänden sowie die Kontrolle der Aktivitäten der Bearbeiter.
Grundlage der Projektmanagement-Aktivitäten bilden Dokumente spezieller Typen,
z.B. Aktivitätengraphen, Balkendiagramme usw. Gegenstand der Prozess-modellierung ist die Formalisierung und Computerunterstützung des Software-entwicklungsprozesses selbst. Neben Bausteinen und Ergebnissen müssen Aufgaben und Ressourcen verwaltet werden. Wichtig ist dabei die Konsistenzsicherung.
5.5 Konfigurationsmanagement
Das Konfigurationsmanagement umfasst Aufgaben wie
•
•
•
die Kontrolle der entwickelten Quellprogramme
die Bereitstellung von „build“-Funktionalität
das Release-Engineering
Das Concurrent Versions System (CVS) ist ein Versionsverwaltungssystem, das
das Versionsmanagement auf der Ebene von Quellprogrammen unterstützt. Es ermöglicht die Aufzeichnung der Entwicklungsgeschichte von Programmdokumenten
in Projekten und unterstützt die Gruppenarbeit (check out –check in).
Neuere Versionsverwaltungssysteme sind Subversion und Mercurial. In Eclipse wird
Versionsverwaltung durch spezielle Plug-ins unterstützt (z.B. Mercurial:
http://www.javaforge.com/project/HGE).
Weitere Werkzeuge wie Ant und Maven dienen der Unterstützung des Build-Prozesses.
6 Wiederverwendung
6.1 Komponentenbasierte Softwareentwicklung - Frameworks
Klassen realisieren „Abstrakte Datentypen“. Sie verkörpern Objektfabriken, weil sie
Operationen zum Erzeugen von Exemplaren (Konstruktoren) zur Verfügung stellen.
Wiederverwendung individueller Komponenten ist nicht kostenlos. Es entsteht Aufwand für das Ausfindigmachen nachnutzbarer Komponenten. OO-Sprachen allein
garantieren keine Verbesserung der Wiederverwendbarkeit.
28
Sächs. VWA
Fritzsche: Software-Engineering
Ein Framework ist eine Sammlung verschiedener individueller Komponenten mit definiertem Kooperationsverhalten zur Lösung einer Aufgabe. Frameworks definieren
in der Regel einen Großteil der Architektur. Wieder-verwendbare Architekturansätze
standardisieren langfristig Anwendungsgebiete.
Whitebox-Frameworks bestehen aus einer Anzahl unvollständig spezifizierter Klassen, d.h. Klassen mit abstrakten Methoden. Diese abstrakten Methoden heißen Einschubmethoden. Um ein Whitebox-Framework anzupassen, muß der Programmierer die Implementation des Frameworks weitgehend kennen.
Blackbox-Frameworks gehen von einer Anzahl fertiger Komponenten aus. Anpassungen des Frameworks werden durch Kompositionen der Komponenten erreicht,
nicht durch Vervollständigung von Klassen.
6.2 Entwurfsmuster
Ein wesentlicher Beitrag zur Thematik der Entwurfsmuster wurde von E. Gamma
geleistet. Gamma et al. haben einen Katalog mit 23 Entwurfsmustern beschrieben.
Bekannte Entwurfsmuster sind das „Beobachter“-Muster, das „Kompositum“-Muster
und das „Strategie“-Muster. Sie finden u.a. in der Model-View-Controler-Architektur
Anwendung.
Beobachter-Muster: Definiere eine 1-zu-n-Abhängigkeit zwischen Objekten, so dass
die Änderung des Zustandes eines Objektes dazu führt, dass alle abhängigen Objekte benachrichtigt und automatisch aktualisiert werden.
Kompositum-Muster: Füge Objekte zu Baumstrukturen zusammen, um Teil-GanzesHierarchien zu repräsentieren. Das Kompositionsmuster ermöglicht es Klienten, einzelne Objekte sowie Kompositionen von Objekten einheitlich zu behandeln.
Strategie-Muster: Definiere eine Familie von Algorithmen, kapsele jeden einzelnen
und mache sie austauschbar. Das Strategie-Muster ermöglicht es, den Algorithmus
unabhängig von ihn nutzenden Klienten zu variieren.
6.3 Grafische Benutzeroberflächen
In Java existiert eine sehr gute Unterstützung für die Entwicklung von Oberflächen
durch das „Abstract Window Toolkit“ (AWT) und das Paket „Swing“. Der Aufbau der
AWT-Klassenbibliothek ist ein Beispiel für die Anwendung des Entwurfsmusters
„Kompositum“.
Layout-Manager nehmen dem Anwender die Arbeit der absoluten Positionierung
von Komponenten in Containern ab. Sie definieren Regeln, nach denen Komponenten in einem Container platziert werden. Es gibt eine Vielzahl von einfach handhabbaren bis hin zu komfortablen Layouts: BorderLayout, FlowLayout, GridLayout, GridBagLayout, usw.
6.4 Die Model-View-Controller-Architektur
Das Model-View-Controller-Prinzip bietet einen Ansatz für die Architektur von Anwendungen, die aus einer grafischen Benutzeroberfläche, einem funktionalen Kern
und einer Datenverwaltung bestehen sollen. Ein Model-Objekt stellt das Anwendungsobjekt dar, das View-Objekt seine Bildschirmrepräsentation und das Controller-Objekt bestimmt die Möglichkeiten, mit denen auf Benutzereingaben reagiert
werden kann. View und Model werden durch den Aufbau eines Protokolls zur Benachrichtigung entkoppelt. Der Antwortmechanismus der Oberfläche wird in einem
Controller gekapselt.
29
Sächs. VWA
Fritzsche: Software-Engineering
Die MVC-Architektur verwendet die Entwurfsmuster Beobachter und Strategie und
Kompositum. Ein oder mehrere Beobachter melden sich beim Model-Objekt an und
werden von diesem benachrichtigt, sobald das Model-Objekt seinen Zustand ändert.
Das Model-Objekt liefert selbst keine Daten an vorhandene Beobachter, diese holen
sich die Informationen vom Model-Objekt, die sie jeweils benötigen.
30
Herunterladen