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äten-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. Addison-Wesley, 8. Aufl. 2007 Rational Software Corporation Homepage: http://www-01.ibm.com/software/rational/ 2 Sächs. VWA Fritzsche: Software-Engineering 1 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 zugrunde gelegt. Bekannte Lebenszyklusmodelle sind u.a. das Wasserfallmodell und das Spiralmodell (letzteres ist ein evolutionäres 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 bei Vorliegen formaler Spezifikationen) und Test (Unit-Test, Integrationstest, Systemtest; teilweise auch entwicklungsbegleitend). Es existiert nicht eine allgemein anerkannte Entwicklungsmethodik, sondern eine Methodologie (Lehre von den Methoden ...) der Softwareentwicklung. Wichtige Aspekte der Softwaretechnologie sind die Entwicklung „großer“ Systeme (Entwicklergruppen über längere Zeit) 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 1.2 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. Diagrammtypen: Use-Case-Diagramm (use case diagram) Klassenstruktur-Diagramm (static structure diagram) Sequenz-Diagramm (sequence diagram) Kommunikations-Diagramm (communication diagram) 3 Sächs. VWA Fritzsche: Software-Engineering Zustands-Diagramm (statechart diagram) Aktivitäten-Diagramm (activity diagram) Komponenten-Diagramm (component diagram) Verteilungs-Diagramm (deployment diagram) 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 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 (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 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. 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. Eine Klassendefinition umfasst (evtl. implizit) eine Beschreibung einer Vorschrift zur Erzeugung von Instanzen. Klassenbildung ist Abstraktion (bei einer Abstraktion 4 Sächs. VWA Fritzsche: Software-Engineering werden 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. 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), 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. Dieser Wert 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 des 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 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 Objekt angewendet werden. 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 dargestellt. Sie können einen Namen besitzen oder auch unbenannt sein. In jedem Fall wird nach dem Doppelpunkt 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. 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 Instanziierungsrelation: Person name:string vorname:string geschlecht:char geburtsjahr:int +alter:int Max:Person Moritz:Person 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 Sächs. VWA Fritzsche: Software-Engineering # ~ protected package wide (Packages werden weiter unten beschrieben) Konstruktoren sind spezielle Operationen, die der Erzeugung von Objekten dienen. Objekte existieren solange, solange sie referenzierbar sind oder bis sie explizit aus der Objektwelt entfernt werden. 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 mehr Klassen. In der grafischen Darstellung werden die Symbole der beteiligten Klassen durch eine durchgezogene Linie verbunden. Die Enden einer Assoziationslinie können mit demselben Klassensymbol verbunden sein. Assoziationen höherer Ordnung (ternäre, ...) werden durch einen Rhombus dargestellt, der durch Linien mit den Klassensymbolen verbunden ist. Assoziationen höherer Ordnung sollten nach Möglichkeit vermieden werden. Sie sind schwerer zu verstehen, darzustellen und zu implementieren als binäre Assoziationen. Assoziationen können 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 setzt eine Anzahl von Objekten entsprechend der Assoziation in Beziehung. Ist durch eine binäre Assoziation eine Klasse mit sich selbst verbunden, können unterschiedliche Objekte dieser Klasse verknüpft sein oder ein Objekt mit sich selbst. Verknüpfungen verbinden im Klassenstrukturdiagramm Instanzobjekte. Beispiele: 7 Sächs. VWA Fritzsche: Software-Engineering 8 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. Class1 Class2 1..* Sächs. VWA Fritzsche: Software-Engineering 9 Ein Objekt der Klasse 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 Absätzen, die ihrerseits aus mindestens einem Satz bestehen. Dokument Absatz Satz 1..* 1 Polygon 1 1 Verbund GrafikVerbund 1..* 3..* {ordered} Eckpunkt Punkt y:real x:real farbe:Farbe texture:Texture Ein Polygon hat mindestens drei Eckpunkte. Die Farbe und andere Eigenschaften sind dem Polygon fest zugeordnet. 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). Generalisierung und Spezialisierung werden zunächst auf Klassen angewendet. Sächs. VWA Fritzsche: Software-Engineering 10 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 ein" (is-a) Säugetier. 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 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. Sächs. VWA Fritzsche: Software-Engineering 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), 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 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 BinWTree mit den Attributen "linker 11 Sächs. VWA Fritzsche: Software-Engineering Nachfolger" (lsucc) und "rechter Nachfolger" (rsucc). Die Attribute sind vom Typ BinWTree, d.h. entsprechende Attribute können Referenzen auf Objekte vom Typ BinWTree 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ß. Jede Unruhe verwaltet ein Objekt vom Typ BinWNode. Das Attribut key der Klasse BinWNode 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 BinWTree angewendet, liefert sie bei Blattelementen den Wert von key und sonst die Summe der Gewichte der Nachfolgerknoten. Die Klasse BinWTreeA spezialisiert die Klasse BinWTree 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 BinWTree an BinWTreeA vererbt. Die Methode balancedp() kann sowohl auf Instanzen von BinWTree als auch von BinWTreeA 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“. 12 Sächs. VWA Fritzsche: Software-Engineering 13 BinWTree BinWNode -node:BinWNode -lsucc:BinWTree -rsucc:BinWTree -key:int 1 +selKey:int +selWeight:int +setKey:void +setWeight:void +weight:int +balancedp:boolean +insLeft:void +insRight:void +insKeyWeight:void 0..1 0..1 BinWTreeA -larm:int -rarm:int +balancedp:boolean +insRarm:void +insLarm:void 2.9 Abstrakte und konkrete Klassen Eine abstrakte Klasse ist eine Klasse, die selbst keine direkten Instanzen besitzt, deren Nachkommen aber direkte Instanzen besitzen. 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. 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: 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 einer Klasse assoziiert ist, ein Objekt 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 2. dynamisch, durch Anwendung eines Konstruktors der entsprechenden Klasse während der Ausführung einer Methode. Objektzustände: vordefinierte Ausprägungen für Zustände von Objekten sind nicht existent (Widerspruch!) 14 Sächs. VWA Fritzsche: Software-Engineering 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, imSpeicher. 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 (invocation) Ereignisse Ein Sequenzdiagramm zeigt das Verhalten von Objekten 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. 15 Sächs. VWA Fritzsche: Software-Engineering Object1 16 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 keine Dauer. Der Zustand eines Objektes bestimmt die Reaktion des Objektes 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 17 Transitionen 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: reservieren()[freiePl舩ze > 1] Ohne Reservierung teilweise reserviert entry()/ruecksetzen reservieren() stornieren()[reserviertePl舩ze = 1] flug_einrichten() flug_streichen() stornieren()[reserviertePl舩ze > 1] stornieren() schliessen() reservieren()[freiePl舩ze = 1] geschlossen ausgebucht schliessen() 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 18 2.12 Aktivitäten-Diagramme Das Aktivitäten-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): Sächs. VWA Fritzsche: Software-Engineering Activity1 Activity2 Activity3 Activity4 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. JavaApplikationen 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 .java-Datei erzeugt, die den Programmtext enthält. 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]); 19 Sächs. VWA Fritzsche: Software-Engineering } } Die Hauptklasse einer Anwendung (z.B. MyApplication) muß die Methode main() implementieren. Mit static gekennzeichnete Methoden oder Variablen beziehen sich auf eine Klasse 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 mainMethode auf solche Parameter zugegriffen werden. Zur Verwaltung der Länge eines Arrays besitzt jedes Array das Feld length. Auf dieses Feld wird wie auf eine Instanzvariable eines Objektes zugegriffen. Strings 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:") 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. 20 Sächs. VWA Fritzsche: Software-Engineering </applet> </body> </html> Ein Browser, der das Applet-Tag nicht kennt, überliest es. Alternative HTMLElemente 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.*; 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); } } Der Netscape-Navigator gibt Ausgaben auf der Standardausgabe über die "JavaConsole" 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. 21 Sächs. VWA Fritzsche: Software-Engineering 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 BinWTree, BinWTreeA und BinWNode. public class BinWTree{ BinWNode root = new BinWNode(); BinWTree lsucc,rsucc; void insKeyWeight(int pkey,int pweight){ root.setKey(pkey); root.setWeight(pweight); } void insLeft(BinWTree tree){ lsucc = tree; } void insRight(BinWTree tree){ rsucc = tree; } int weight(){ if (root.selWeight() == 0) return( lsucc.weight() + rsucc.weight() ); else return( root.selWeight()); } boolean balancedp(){ if (root.selWeight() == 0) return( lsucc.balancedp() && rsucc.balancedp() && (lsucc.weight() == rsucc.weight())); else return(true); } void makebalance(){ } } class BinWTreeA extends BinWTree{ int larm,rarm; void insLarm(int parm){ larm = parm; } void insRarm(int parm){ rarm = parm; } boolean balancedp(){ if (root.selWeight() == 0) return( lsucc.balancedp() && rsucc.balancedp() && (larm * lsucc.weight() == rarm * rsucc.weight())); else return(true); } void makebalance(){ 22 Sächs. VWA Fritzsche: Software-Engineering int s = larm + rarm; if (root.selWeight() == 0){ lsucc.makebalance(); rsucc.makebalance(); if (!(this.balancedp())){ rarm = lsucc.weight()*s/this.weight(); larm = s - rarm;} System.out.println(larm); System.out.println(rarm); } } } class BinWNode{ int key,weight; int selWeight(){ return(weight); } int selKey(){ return(key); } void setWeight(int pweight){ weight = pweight; } void setKey(int pkey){ key = pkey; } } Die Klasse UseBinWTree bietet eine beispielhafte Anwendung: public class UseBinWTree { public static void main(String args[]){ System.out.println("Hello world!"); BinWTree m1 = new BinWTree(); m1.insKeyWeight(1,0); BinWTree m2 = new BinWTree(); m2.insKeyWeight(2,4); BinWTree m3 = new BinWTree(); m3.insKeyWeight(3,0); BinWTree m4 = new BinWTree(); m4.insKeyWeight(4,0); BinWTree m5 = new BinWTree(); m5.insKeyWeight(5,1); BinWTree m6 = new BinWTree(); m6.insKeyWeight(6,1); BinWTree m7 = new BinWTree(); m7.insKeyWeight(7,2); 23 Sächs. VWA Fritzsche: Software-Engineering m4.insLeft(m5);m4.insRight(m6); m3.insLeft(m4);m3.insRight(m7); m1.insLeft(m2);m1.insRight(m3); System.out.println(m1.weight()); System.out.println(m1.balancedp()); BinWTreeA ma1 = new BinWTreeA(); ma1.insKeyWeight(1,0); BinWTreeA ma2 = new BinWTreeA(); ma2.insKeyWeight(2,3); BinWTreeA ma3 = new BinWTreeA(); ma3.insKeyWeight(3,0); BinWTreeA ma4 = new BinWTreeA(); ma4.insKeyWeight(4,0); BinWTreeA ma5 = new BinWTreeA(); ma5.insKeyWeight(5,2); BinWTreeA ma6 = new BinWTreeA(); ma6.insKeyWeight(6,1); BinWTreeA ma7 = new BinWTreeA(); ma7.insKeyWeight(7,1); ma4.insLeft(ma5);ma4.insRight(ma6); 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 UseBinWTree Hello world! 8 true 7 24 Sächs. VWA Fritzsche: Software-Engineering true 7 false 2 4 1 3 4 3 7 true Bye world! 3.3 Interfaces und Mehrfachvererbung In Java gibt es 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 ihre Methoden überschreiben. Die Eigenschaft einer Klasse, ein Interface zu implementieren, wird an ihre Nachfahren vererbt. 3.4 Implementation von Assoziationen und Aggregationen Zur Implementation von Assoziationen und Aggregationen mit 1:n – Beziehungen eignen sich Vektoren und Hash-Tabellen. 25 Sächs. VWA Fritzsche: Software-Engineering Ein Vektor ist in Java (als Instanz der Klasse Vector) ein eindimensionales dynamisches Array. Methoden sind addElement, insertElement, removeElement. Die Methode size liefert 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 Hashtable verfügbar. 3.5 Dynamische Modelle und Event-Handling Ziel ist hier die Umsetzung von Zustandsdiagrammen in Java-Programme. Bei jeder Mausbetätigung 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 Event-Quelle kann es andererseits auch mehrere Listener geben. import java.applet.*; import java.awt.event.*; import java.awt.*; 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 26 Sächs. VWA Fritzsche: Software-Engineering 27 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 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 Sächs. VWA Fritzsche: Software-Engineering 28 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 UseCaseDiagramme. 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 benutzt-Beziehungen (<<uses>>) und Generalisierungen/Spezialisierungen (<<extends>>) zwischen Anwendungsfällen gezeigt werden. Autovermietung Interessent beraten Kunde reservieren Reservierungsmitarbeiter Vertrag schlie゚en ワbergabemitarbeiter Fahrer KFZ ・ergeben KFZ zur・knehmen Kunde R・knahmemitarbeiter abrechnen 5.2 Methodische Aspekte der Modellierung In der Analysephase sind folgende Aktivitäten erforderlich: Zerlegung des Anwendungsbereiches in Unterbereiche Sächs. VWA Fritzsche: Software-Engineering Analyse und Spezifikation des geforderten Systemverhaltens Während der Problembereichsanalyse werden zunächst „Geschäftsklassen“ modelliert. „Fachklassen“ beschreiben im Unterschied dazu implementierungstechnische 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, der symbolische Test und dynamische Analysen („Testen“). Zu den statischen Analysen zählen Kontrollfluss- und Datenflussanalyse sowie die Programmverifikation. 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 Prozessmodellierung ist die Formalisierung und Computerunterstützung des Softwareentwicklungsprozesses 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 29 Sächs. VWA Fritzsche: Software-Engineering Das Concurrent Versions System (CVS) ist ein System, 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). 6 Wiederverwendung 6.1 Komponentenbasierte Softwareentwicklung Frameworks Klassen realisieren „Abstrakte Datentypen“. Sie verkörpern Objektfabriken, weil sie Operationen zum Erzeugen von Exemplaren 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. 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. Wiederverwendbare 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. 30 Sächs. VWA Fritzsche: Software-Engineering 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 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. 31