proceedings seminar 1908 - fernuniversität hagen · komponenten in .net, angela grüner, florian...

169
Proceedings Seminar 1908 July 3, 2006

Upload: others

Post on 19-Oct-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

  • Proceedings Seminar 1908

    July 3, 2006

  • Contents

    Aspectual Collaboration - Komponenten und die aspektorientierte Programmierung,Michael Hahn, Thomas Pawlitzki 2

    Komponenten in UML 2.0,Lars Greiffenhagen, Peter Stumfol 21

    Das CORBA Komponentenmodell,Harald Waldhäuser, Vera Mathiak 41

    Komponenten in .NET,Angela Grüner, Florian Kintzel 62

    Komposition von Komponenten mit Dependency Injection am Beispiel des Spring-Frameworks,Antje Fuhrmann, Martin Schaaf 78

    Komponenten in Java und J2EE,Frank Fiedler, Thorsten Schülein 101

    Komponentenorientierte Programmiersprachen,Karlheinz Zugsbratl, Viet Hai Pham 125

    Die Eclipse Rich-Client-Platform (RCP),Mario Bertschler, Thomas Klinkert 141

    1

  • Aspectual Collaboration

    Komponenten und die aspektorientierte Programmierung

    Seminararbeit im Sommersemester 2006

    „Komponentenbasierte Programmierung“

    an der Fern-Universität Hagen

    Verfasser:

    Michael Hahn

    Thomas Pawlitzki

    - 1 -2

  • Inhaltsverzeichnis

    0 Überblick........................................................................................................................................................ 3

    1 Einleitung....................................................................................................................................................... 3

    1.1 Motivation.............................................................................................................................................. 3

    1.2 Abgrenzung........................................................................................................................................... 3

    2 Modulare Programmierung............................................................................................................................ 4

    2.1 Aufteilung in Module.............................................................................................................................. 4

    2.2 Fallbeispiel: Objektpersistenz (Modul)................................................................................................... 5

    2.3 Probleme............................................................................................................................................... 6

    3 Aspektorientierte Programmierung................................................................................................................ 7

    3.1 Trennung der Anforderungen................................................................................................................. 7

    3.2 Begriffe.................................................................................................................................................. 8

    3.3 Fallbeispiel: Objektpersistenz (Aspekt).................................................................................................. 9

    3.4 Probleme............................................................................................................................................... 9

    4 Aspectual Collaboration............................................................................................................................... 10

    4.1 Das Modell der Aspectual Collaborations............................................................................................ 10

    4.2 Collaborations...................................................................................................................................... 11

    4.2.1 Aufbau und Begriffe..................................................................................................................... 11

    4.2.2 Anwendung der Collaborations.................................................................................................... 13

    4.3 Fallbeispiel: Objektpersistenz (Aspectual Collaboration)..................................................................... 15

    4.4 Weitere Implementierungen................................................................................................................. 16

    4.4.1 Aspectual Collaboration............................................................................................................... 17

    4.4.2 CaesarJ Projekt........................................................................................................................... 17

    4.5 Probleme............................................................................................................................................. 18

    5 Zusammenfassung...................................................................................................................................... 18

    6 Literatur........................................................................................................................................................ 19

    - 2 -3

  • 0 Überblick

    Dieser Artikel soll zum einen eine Einführung in den Ansatz und das Modell der Aspectual Collaboration

    (nach [HE2002]) geben, aber auch die Legitimation für einen solchen Ansatz verdeutlichen, indem Schwä-

    chen bzgl. der Kapselung und Wiederverwendung von Sowftwarebausteinen bei der modularen Program-

    mierung (Module) und der aspektorientierten Programmierung (Aspekte) aufgezeigt werden.

    1 Einleitung

    Softwareprojekte sollen in Industrie und Wirtschaft immer schneller zu immer geringeren Kosten abgeschlos-

    sen werden. Die Komplexität der zu lösenden Probleme nimmt dabei ständig zu. Gleichzeitig wird natürlich

    bleibend hohe Softwarequalität erwartet. Daher kommt es mit zunehmendem Maße darauf an, frühzeitig auf

    die richtige Softwaretechnologie und möglichst effizient einsetzbare Entwicklungswerkzeuge zu setzen. Die

    Entwicklung von und der Einsatz schon vorhandener lose gekoppelten, wiederverwendbaren Komponenten-

    strukturen (Kollaborationen) verspricht diesem Ziel näher zu kommen.

    1.1 Motivation

    Die objektorientierte Programmierweise hat ihr Versprechen, über Projektgrenzen hinweg wiederverwendba-

    re Softwareartefakte zu schaffen, bisher nicht einlösen können. Schnittstellen ermöglichen zwar die notwen-

    dige Abgrenzung, um gleichzeitig parallel an verschiedenen Teilen eines Projektes zu entwickeln, ermögli-

    chen durch ihre stark projektspezifische Struktur aber selten die Wiederverwendung in Folgeprojekten. Ne-

    ben der Objektorientierung hat sich in der letzten Zeit die Aspektorientierung zu einer wichtigen Größe in der

    Softwarewelt entwickelt. Aspekte ermöglichen es quer schneidende Belange, wie z. B. Logging, Fehlerbe-

    handlung, Transaktionssteuerung, übergreifend in eigene austauschbare Artefakte auszulagern. Diese Funk-

    tionalität ist nun also nicht mehr notwendigerweise über viele Klassen eines Projektes verstreut und damit

    auch nicht mehr stark mit der implementierten Logik der anderen Anwendungsfälle vermengt. Das Konzept

    der „Aspectual Collaboration“ versucht nun diese ausgelagerten Aspekte so zu strukturieren, dass auch sie

    als Bausteine über Projektgrenzen hinweg wiederverwendbar werden, also nur lose in so genannten Kolla-

    borationen miteinander gekoppelt sind.

    1.2 Abgrenzung

    Diese Arbeit soll den Problemkreis der begrenzten projektübergreifenden Wiederverwendbarkeit von Softwa-

    rekomponenten vorstellen und den Einsatz von Aspectual Collaborations als einen möglichen Lösungsan-

    satz aufzeigen. Dabei können nicht alle Aspekte der modularen und aspektorientierten Programmierung an-

    gesprochen werden. Auch kann das Thema der Arbeit nur einführend behandelt und für ein tieferes Ver-

    ständnis der Aspectual Collaborations muss auf die angegebene Literatur verwiesen werden. Weiterhin

    deckt das beleuchtete Fallbeispiel nur einen sehr geringen Teil der zur Verfügung stehenden Möglichkeiten

    - 3 -4

  • des Konzeptes der Aspectual Collaborations ab. Es wurde mit Hilfe der objektorientierten Programmierspra-

    che Java entwickelt, durch die aspektorientierte Erweiterung AspectJ ([ASPECTJ]) ergänzt und später wei-

    terführend durch den Ansatz der ObjectTeams ([ObjTeams]) implementiert. Andere Implementierungen der

    vorgestellten Konzepte werden nicht näher betrachtet.

    Auch geht diese Arbeit nicht genauer auf die komponentenbasierte Programmierung ein. Ascpectual Colla-

    borations sind unserer Meinung nach eher als Module anzusehen, da ihnen ein Komponentenmodell fehlt,

    welches die Kommunikation und den Lebenszyklus der Komponenten regelt und den Komponenten unter

    Umständen weitere Dienste anbieten kann.

    2 Modulare Programmierung

    Die modulare Programmierung versucht der Motivation aus 1.1 gerecht zu werden, indem sie die immer

    komplexer werdenden Softwaresysteme in kleinere Einheiten zerlegt. Diese kleineren funktionell abge-

    schlossenen Einheiten nennt man Module. Im Folgenden sollen das Vorgehen und die Vorteile der modula-

    ren Programmierung in 2.1 und die Probleme in 2.3 erläutert werden. Der mögliche Aufbau eines einfachen

    Moduls wird an einem kleinen Fallbeispiel in 2.2 illustriert.

    2.1 Aufteilung in Module

    Wie schon kurz erwähnt, versucht man die Komplexität eines Softwaresystems bei der modularen Program-

    mierung durch Unterteilung des Systems in funktional unabhängige Einheiten zu reduzieren. Dies ermöglicht

    den Entwicklern Teile des gesamten Softwaresystems separat zu entwickeln und zu einem späteren Zeit-

    punkt zu dem gesamten System zusammen zu setzen. Durch das Zerlegen des Systems in Einheiten ist da-

    mit eine zeitlich unabhängige und örtlich getrennte Entwicklung von Softwareteilen möglich. Dadurch können

    bei der Projektplanung auch parallel und fremd entwickelte Module berücksichtigt werden. (vgl. [WPMP] und

    [WA04])

    Das Entwickeln in Modulen erlaubt es also, die selbst implementierten oder zugekauften Module in anderen

    Softwaresystemen wiederzuverwenden, oder komplexere Module aus anderen Modulen aufzubauen. Dazu

    ist es allerdings notwendig, dass ein Modul eine klar spezifizierte öffentliche Schnittstelle besitzt, welche es

    ermöglicht, es von außen anzusprechen und zu benutzen. Somit besteht ein Modul nach [WA04] aus:

    • der öffentlichen Schnittstelle des Moduls

    • der Implementierung des Moduls

    Ein Vorteil dieser Trennung ist, dass Änderungen an dem Modul, welche nicht die öffentliche Schnittstelle

    betreffen, auf die Modulimplementierung begrenzt bleiben. Damit müssen Änderungen nur lokal und inner-

    halb des Moduls umgesetzt werden. Die Programmstellen, an denen das Modul benutzt wird, sind von den

    Änderungen also nicht betroffen (vgl. [01853], S. 172). Weiterhin kann man an der Schnittstelle und ihrer

    Spezifikation die Funktion des Moduls ablesen, ohne dessen Implementierung kennen zu müssen. Somit

    - 4 -5

  • werden Informationen über das Modul und der interne Zustand des Moduls durch die Schnittstelle versteckt

    und es kann nur über die Methoden der Schnittstelle auf die Funktionalität des Moduls zugegriffen werden.

    2.2 Fallbeispiel: Objektpersistenz (Modul)

    Die Schnittstelle eines Moduls, welches Objekte persistent machen kann, könnte wie folgt aussehen. Sie bie-

    tet eine öffentliche Klasse mit einer statischen Methode (Zeilen 4-8), welche eine Instanz der Implementie-

    rung zurück gibt. Durch diese Factory-Methode bleibt der Client des Moduls von der Implementierung ent-

    koppelt. Außerdem werden für eine Implementierung des Interfaces zwei weitere Methoden definiert. Die

    eine Methode kann ein Objekt speichern (Zeile 10-11), wogegen die Andere es ermöglicht ein vorher persis-

    tent gemachtes Objekt zu laden (Zeile 13-14).

    1 package fallbeispiele.persistenz.modul; 2 3 public interface Persister { 4 public class Factory { 5 static public Persister getInstance() { 6 return PersisterImpl.getInstance(); 7 } 8 } 9 /** Persitiert ein Objekt in einer Datei */ 10 public void saveObject(String path, java.io.Serializable s) 11 throws java.io.IOException; 12 /** Läd ein persistiertes Objekt aus einer Datei */ 13 public Object loadObject(String path) 14 throws java.io.IOException, ClassNotFoundException; 15 }

    Eine beispielhafte Implementierung des Interfaces und damit des Moduls zeigen die Zeilen 16-29 im folgen-

    den Quelltextblock. Die PersisterImpl Klasse implementiert das oben beschriebene Interface und kann somit überall dort verwendet werden, wo die von der Schnittstelle bereitgestellte Funktionalität benötigt wird.

    Wie in der Factory-Methode des Interfaces (Zeile 6) gefordert, muss die Klasse, neben der Implementierung

    der beiden Methoden zum Speichern und Laden von Objekten, auch noch eine statische Methode getIn-stance() bereitstellen, die eine Instanz der Klasse PersisterImpl ggf. erstellt und zurück gibt.1 Da die Implementierung des Moduls keinen Zustand hat und somit für alle Nutzer des Moduls gleich ist, kann sie

    nach dem Singleton-Pattern2 realisiert werden.

    16 package fallbeispiele.persistenz.modul; 17 18 import java.io.*; 19 20 class PersisterImpl implements Persister{ 21 22 private static Persister instance = null; 23 private PersisterImpl() {} 24 25 public static Persister getInstance() {

    1 Dadurch ist zwar das Interface an die implementierende Klasse gekoppelt, aber da es sich bei dem Interface um ein

    idiosynkratisches Interface handelt, existiert in dem Programm sowieso nur eine Implementierung für das Interface.

    2 Das Singleton-Pattern bewirkt, dass in dem ganzen Programm nur eine Instanz der Klasse existiert.

    - 5 -6

  • 26 if (instance == null) instance = new PersisterImpl(); 27 return instance; 28 } 29 30 public void saveObject(String path, Serializable s) throws IOException { 31 ObjectOutputStream oos = 32 new ObjectOutputStream(new FileOutputStream(path)); 33 oos.writeObject(s); 34 oos.flush(); 35 oos.close(); 36 } 37 38 public Object loadObject(String path) throws IOException, ClassNotFoundException { 39 ObjectInputStream ois = 40 new ObjectInputStream(new FileInputStream(path)); 41 Object o = ois.readObject(); 42 ois.close(); 43 return o; 44 } 45 }

    Ein Client, der nun mit Hilfe des oben beschriebenen Moduls ein Objekt in einer Datei speichern oder ein

    Objekt aus einer Datei laden möchte, holt sich zunächst eine Instanz des Interface-Typs über die Factory-

    Methode (Zeile 47). Mit dieser Instanz kann er nun die Methoden saveObject() (Zeile 51) und loadOb-ject() (Zeile 55) des Moduls verwenden.

    46 // ... 47 Persister persister = Persister.Factory.getInstance(); 48 // ... 49 // Object foo der Klasse Foo soll gespeichert werden 50 // (Foo muss java.io. Serializable implementieren) 51 persister.saveObject(„./foo.obj“, foo); 52 53 // ... 54 // Object foo soll wieder geladen (und gecast) werden 55 Foo foo = (Foo) persister.loadObject(„./foo.obj“); 56 // ...

    2.3 Probleme

    Modularisierung im Kontext der Software-Entwicklung ermöglicht es schon implementierte Module in neuen

    Programmen wieder zu verwenden oder als Bausteine zum Erstellen von komplexeren Modulen einzuset-

    zen.

    Allerdings stößt man bei der Zuordnung der Verantwortungen eines Moduls auch an Grenzen. Bei der Zerle-

    gung der Anforderungen in funktionell abgegrenzte Einheiten kann man einige Funktionen zwar konzeptio-

    nell isolieren, aber es ist nicht möglich die Funktionen in einem Modul zu isolieren. ([01853], S. 173) Bei der

    Realisierung nehmen solche Funktionen auf mehrere Module Einfluss und schneiden somit die eigentliche

    Ordnung der Funktionen nach Modulen quer. Aus diesem Grund werden diese Funktionen auch cross cut-

    ting concerns3 genannt. Typische Beispiele für solche eine Funktionalität sind Logging, Persistenz oder Feh-

    lerbehandlungen. ([WPCCC])

    3 Die Funktionen, die sich in einem Modul isolieren lassen, sind die core concerns. Siehe hierzu auch 3.1.

    - 6 -7

  • Für das Fallbeispiel aus 2.2 würde dies bedeuten, dass sich immer dann, wenn das Modul Persister be-nutzt werden soll, Funktionsaufrufe des Moduls im Quellcode wiederfinden lassen. Diese Funktionsaufrufe

    sind also mit der eigentlichen Funktionalität des Codes verzahnt und daher nicht sauber gekapselt4.

    Demnach stellt es sich als problematisch heraus, ein zweidimensionales Problem - Trennen der Kernfunktio-

    nalität und Isolieren der quer schneidenden Funktionalität - als eindimensionale Lösung modulieren zu wol-

    len ([01853], S. 173f). Die quer schneidende Funktionalität findet sich in allen Modulen wieder. Dies zwingt

    zu redundantem Code (scattering und tangling5) und führt damit zu schlechter Wartbarkeit, schlechter Über-

    sichtlichkeit und Fehleranfälligkeit des gesamten Systems.6

    Die Dekomposition des Systems in Module reicht allein also nicht aus, da man neben der Trennung der

    Kernfunktionalität (core concerns) auch noch die Kapselung der quer schneidenden Funktionalität erreichen

    möchte. Aspektorientiertes Programmieren versucht dieses Problem durch die Einführung einer weiteren

    Möglichkeit der Ordnung von Funktionalität zu lösen. Dieser Ansatz wird im nächsten Kapitel erläutert.

    3 Aspektorientierte Programmierung

    Eine weitere Herangehensweise den in 1.1 aufgezeigten Zielen näher zu kommen, stellt die Verwendung der

    aspektorientierten Programmierung (englisch: aspect oriented programming, kurz AOP) dar ([WPAOP]). Sie

    basiert auf der im vorherigen Kapitel 2 eingeführten Methodik. Der hier betrachtete weitergehende Ansatz

    bietet die Möglichkeit übergreifende in verschiedenen Modulen immer wiederkehrende Aspekte in separate

    Programmfragmente auszulagern. Die hiermit verbundenen Vorteile bzw. Probleme sollen in 3.1und 3.4 nä-

    her betrachtet werden. Neu eingeführte Begriffe erläutert Abschnitt 3.2 Außerdem wird das Fallbeispiel Per-

    sistenz in 3.3 fortgeführt.

    3.1 Trennung der Anforderungen

    Neben den in gekapselten Modulen umsetzbaren funktionalen Anforderungen gibt es oft übergreifende An-

    forderungen an eine Software, welche quer durch alle Module implementiert werden müssen (bspw. Log-

    ging, Fehlerbehandlungen, Persistenz, Transaktionssteuerung). Diese wiederkehrenden und das Programm

    quer schneidenden Anforderungen werden in AOP crosscutting concerns genannt. Wie in Abbildung 1 zu se-

    hen, ist deren Implementierung über mehrere Module verteilt (scattering) und oft mit der Umsetzung der ei-

    gentlichen Kernfunktionalitäten eng verzahnt (tangeling).

    4 Siehe hierzu auch Abbildung 1 in 3.1.

    5 Siehe hierzu 3.1.

    6 Zum Beispiel müssen bei Änderung mehrere Stellen betrachtet, berücksichtigt und angepasst werden.

    - 7 -8

  • Die aspektorientierte Programmierung erlaubt es diese Querschnittsbelange in separate Programmfragmen-

    te, in so genannte Aspekte, auszulagern. Damit wird es möglich, logisch unabhängige Belange auch phy-

    sisch voneinander zu trennen. Die Software wird daher besser wartbar und einzelne Aspekte können ggf. in

    anderen Modulen wiederverwendet werden.

    3.2 Begriffe

    Im Folgenden sollen einige wichtige Begriffe der aspektorientierten Programmierung kurz erläutert werden.

    Joinpoints (Verbindungspunkte) sind Punkte im Programmfluss, an welchen in Advices (siehe unten) imple-mentierte Funktionalität die Programmlogik erweitern oder modifizieren kann. Beispiele für solche Verbin-

    dungspunkte sind der Aufruf oder die Ausführung einer Methode oder eines Konstruktors, die Initialisierung

    eines Objektes, der lesende oder schreibende Zugriff auf ein Feld eines Objektes oder das Ausführen einer

    Fehlerbehandlungsroutine.

    Pointcuts (Schnittpunkte) repräsentieren jeweils eine Untermenge von Joinpoints (einer oder mehrere) ei-nes Programms. Pointcuts können dabei nicht nur vom Ort im Programmfluss sondern auch vom Kontext ih-

    res Aufrufs, z.B. dem Zielobjekttyp des Aufrufs, abhängen.

    Advices (Empfehlungen) werden bei Erreichen eines Joinpoints ausgeführt. Abhängig vom relativen Ausfüh-rungspunkt unterscheidet man zwischen before-, after- und around-Advices, wobei der zusätzliche Pro-

    grammcode vor, nach oder anstatt der durch den Joinpoint selektierten Logik ausgeführt wird.

    Aspekte sind eine Erweiterung des in der objektorientierten Programmierwelt verwendeten Klassenkonzep-tes und Grundlage für die Implementierung der in AOP betrachteten Crosscutting Concerns. Ein Aspekt

    beinhaltet also die Definition von Pointcuts und Advices.

    - 8 -

    Abbildung 1: Scattering und Tangling (in Anlehnung an

    [MO2003],Seite 37)

    9

  • Weaving (Einweben) bezeichnet das Verknüpfen der in Advices implementierten Querschnittsbelange mit den in Modulen umgesetzten funktionalen Anforderungen eines Softwaresystems. Hierzu wird ein AOP-

    Compiler (bspw. AspectJ (siehe [ASPECTJ])) verwendet.

    3.3 Fallbeispiel: Objektpersistenz (Aspekt)

    In diesem Abschnitt soll das in Kapitel 2.2 vorgestellte Beispiel um aspektorientierte Ansätze erweitert wer-

    den. Konkret handelt es sich hierbei um einen Aspekt, welcher den eingeführten Persister verwendet, um bei

    jedem Aufruf einer mit dem Prefix set beginnenden Methode (Setter-Methode) das Zielobjekt zu speichern. Hierzu muss ein Pointcut und ein Advice definiert werden. Der Pointcut (Zeilen 71-72) filtert alle Methoden-

    aufrufe nach set-Methoden. Nach dem Ausführen dieser Methoden ruft der in den Zeilen 75-82 definierte after-Advice die Methode Persister.saveObject(), um das Objekt zu speichern.

    57 package fallbeispiele.persistenz.aop; 58 59 import java.io.Serializable; 60 import fallbeispiele.persistenz.modul.Persister; 61 62 public aspect PersisterAspect{ 63 64 /** referencing the persister singleton instance */ 65 private static final Persister persister = Persister.Factory.getInstance(); 66 67 /** 68 * pointcut that filters all set-Methods. Setters are instance methods 69 * returning void, prefixed "set...". 70 */ 71 public pointcut setters(Object obj): 72 call(void *.set*(..)) && target(obj); 73 74 /** advice that is executed after calling a setter */ 75 after(Object obj): setters(obj){ 76 try{ 77 persister.saveObject("./"+obj.hashCode()+".obj", (Serializable)obj); 78 System.out.println("PersisterAspect: Object stored successfully!"); 79 }catch(Exception e){ 80 System.out.println("PersisterAspect: Object could not be stored!"); 81 } 82 } 83 }

    Die Implementierung eines Clients, der eine Setter-Methode eines beliebigen Objektes aufruft, hat nun nichts

    mehr direkt mit der eigentlichen persistenten Speicherung zu tun, vorausgesetzt der vorgestellte Persis-terAspect wurde mit dem AspectJ-Compiler hinzugewoben (Weaving).

    3.4 Probleme

    Eines der Hauptkritikpunkte an der aspektorientierten Herangehensweise ist der Verlust der Übersichtlichkeit

    des Programmcodes. Bei Betrachtung einzelner Module ist nicht mehr klar ersichtlich, welche in Aspekte

    ausgelagerten Belange neben der an dieser Stelle implementierten Kernfunktionalität außerdem ausgeführt

    werden. Es muss also der Quelltext in seiner Gesamtheit betrachtet werden, um die an einer Stelle ausge-

    - 9 -10

  • führte Logik zu verstehen. Diese Verteilung der nacheinander ausgeführten Programmlogik erschwert zu-

    sätzlich die Fehlersuche (Debugging). Moderne IDEs unterstützen aber inzwischen auch das Debugging von

    aspektorientierten Programmen, was diesen Nachteil zumindest abschwächt. Weiterhin führt der durch das

    Einweben (weaving) der Aspekte in den Programmcode entstandene Overhead im Allgemeinen zu Leis-

    tungseinbußen des generierten Gesamtsystems.

    4 Aspectual Collaboration

    Bei der Entwicklung von modernen Softwaresystemen, deren Komplexität und Größe immer weiter wächst,

    hat sich momentan der Ansatz der Objektorientierung etabliert. Dabei werden Probleme, ähnlich der modula-

    ren Programmierung, in kleinere Einheiten zerlegt. Diese kleineren Einheiten sind Objekte, welche miteinan-

    der agieren, um die Funktionalität des Gesamtsystems anzubieten. Bei der Dekomposition des Systems in

    Objekte kann man die gleichen Probleme beobachten, wie sie auch bei der modularen Programmierung zu

    beobachten sind und in 2.3 beschrieben wurden. Funktionalität verteilt sich über mehrere Objekte hinweg

    (scattering) oder ist mit der Kernfunktionalität des Objektes verzahnt (tangling). Dadurch wird die Verantwor-

    tung eines Objektes für die eigene Funktionalität aufgeweicht.

    Der Ansatz der aspektorientierten Programmierung ermöglicht es zwar Querschnittsbelange zu isolieren. Al-

    lerdings leidet darunter die Übersichtlichkeit des Programms. Außerdem können Aspekte nur schwer wieder-

    verwendet werden. Es werden also Module benötigt, welche die Aspekte eines Softwaresystems kapseln

    und diese auch anderen Softwaresystemen zur Wiederverwendung bereitstellen können.

    Aus verschiedenen Vorläufern, wie z. B. Adaptive Plug and Play ([MMKL98]) oder Aspectual Components

    ([LiLoMe99]), hat sich der Ansatz der Aspectual Collaborations entwickelt. Dieser versucht Module, welche

    quer schneidende Funktionalität kapseln, zu erstellen.

    Um diesen Ansatz genauer zu beleuchten wird zunächst in 4.1 das Modell der Aspectual Collaborations er-

    läutert. In 4.2 wird dann anhand von Objekt Teams7 ([ObjTeams]) eine konkrete Implementierung des Ansat-

    zes vorgestellt. Das Fallbeispiel Persistenz wird in 4.3 aufgegriffen und mit der Object Teams Implementie-

    rung fortgesetzt. Anschließend werden in 4.4 alternative Implementierungen des Ansatzes der Aspectual

    Collaborations skizziert und in 4.5 auftretende Probleme aufgelistet.

    4.1 Das Modell der Aspectual Collaborations

    Durch die Kapselung von Aspekten in Modulen möchte man erreichen, dass sich große und komplexe Soft-

    waresysteme auf einfache Weise erstellen lassen. Weiterhin soll eine Wiederverwendung der Bausteine des

    Systems möglich sein.

    Um diese Ziele zu erreichen werden die Aspekte modularisiert und in Kollaborationen zusammen gefasst.

    Die Kollaborationen bestehen aus mehreren Objekten, die gemeinsam die gewünschte Funktionalität anbie-

    7 Wir haben uns für diese Implementierung entschieden, da sie aktiv weiterentwickelt wird und auch eine gute

    Integration in moderne Entwicklungsumgebungen vorhanden ist.

    - 10 -11

  • ten können. Bestehende Software kann dann durch die Integration dieser Kollaborationen um den in der je-

    weiligen Kollaboration enthaltenen Aspekt erweitert werden. Wie eine solche Integration eines quer schnei-

    denden Aspekte in die Software aussieht, wird in Abbildung 2 verdeutlicht.

    Die bestehenden Klassen (Class A, Class B, Class C) nehmen in verschiedenen Kollaborationen (Collabora-

    tion 1, Collaboration 2, Collaboration 3) verschiedene Rollen ein. Als Beispiel soll das Observer-Muster auf

    diese Abbildung angewendet werden. Dieses Entwurfsmuster sieht vor, dass ein Objekt als Subjekt agiert

    und von anderen Objekten beobachtet werden kann. Wenn sich der Zustand des Subjekts ändert, werden

    die Beobachter des Subjekts benachrichtigt. Unter der Annahme, dass in Abbildung 2 die Kollaboration 2

    das Observer-Muster abbildet, könnte man die Rollen auf die einzelnen Objekte der Klassen A und C wie

    folgt verteilen. Die Klasse A übernimmt in der Kollaboration die Rolle des Subjekt (Role A2). Die Objekte der

    Klasse C übernehmen im Kontext der Kollaboration die Funktion des Beobachters (Role C2).

    4.2 Collaborations

    Im folgenden sollen die Kollaborationen konkret an der Implementierung Object Teams ([ObjTeams]) erläu-

    tert werden. Da die derzeit verfügbaren sprachlichen Mittel der weit verbreitet eingesetzten objektorientierten

    Sprachen für die Modellierung von Kollaborationen nicht ausreichen, müssen hierzu neue Sprachkonstrukte

    eingeführt werden. Object Teams erweitert die Programmiersprache Java um einige Schlüsselworte, mit de-

    nen sich Kollaborationen definieren lassen. Die neu eingeführten Sprachkonstrukte werden in 4.2.1 vorge-

    stellt. Kapitel 4.2.2 beschreibt darauf aufbauend, wie man die mit Object Teams definierten Kollaborationen

    anwendet.

    4.2.1 Aufbau und Begriffe

    Auch wenn der Begriff der Kollaboration sprachlich das in 4.1 vorgestellte Modell sehr gut ausdrückt, hat

    man sich bei der Implementierung von Objekt Teams für einen anderen Namen entschieden. Die Objekte,

    welche für die Realisierung eines Aspektes kollaborieren, werden in so genannten Team-Klassen zusammen

    gefasst. Object Teams definiert dabei die Einheit Team in [HE2002] auf Seite 3 wie folgt:

    - 11 -

    Abbildung 2: Aspectual Collaboration (siehe

    [HE2002], Seite 1)

    12

  • The key concept of Object Teams is a kind of module that combines properties of classes and

    packages. An Object Team is an instantiable aggregation of confined objects called roles.

    Ein Team ist demnach ein Modul, welches mehrere Klassen beinhalten und selbst instantiiert werden kann.

    Außerdem wird gesagt, dass ein Team aus mehreren Objekten besteht, wobei jedes dieser Objekte die

    Funktion einer bestimmten Rolle übernimmt. Für die Einheit Rolle findet man in [HE2002] auf Seite 12 eben-

    falls eine Definition:

    Role objects are dependent objects that reside within an enclosing team instance and also need

    a base instance.

    Eine Rolle ist also ein Objekt, welches fest an eine bestimmte Team-Instanz gebunden ist, wobei die Rolle

    von einer bestimmten Basisinstanz „gespielt“ wird. Mit Basisinstanz ist eine Instanz einer Klasse gemeint,

    welche innerhalb eines Teams eine bestimmte Rolle einnehmen soll. Eine schematische Ansicht der Verbin-

    dung zwischen Team, Rollen und Basisinstanzen ist in Abbildung 3 dargestellt. Die Klassen, deren Instanzen

    die Rollen des Teams übernehmen, werden innerhalb der Team-Klasse definiert. Über das Schlüsselwort

    playedBy werden die Rollen des Teams mit den Basisklassen, welche diese Rollen spielen, verbunden. Hierzu müssen die Basisklassen selbst weder verändert noch angepasst werden.

    Durch die Zuordnung von Rolle zu Basisinstanz ist jetzt zwar definiert, welche Basisklasse welche Rolle in

    der Kollaboration einnimmt, allerdings muss noch festgelegt werden, wie die Funktionalität der Rolle mit der

    Funktionalität der Basis verbunden wird. Object Teams bietet hierzu die Möglichkeit die Methoden der Basis-

    klasse mit den Methoden der Klasse der Rolle zu verknüpfen. Diese Zuordnung wird binding genannt und

    funktioniert sowohl in Richtung Basis->Rolle (callin) als auch in Richtung Rolle->Basis (callout). Veran-schaulicht wird dies in Abbildung 4. [HE2002] bietet hierzu auf Seite 12 folgende Erläuterung an:

    – Callout bindings declare forwarding from a role instance to its base object.

    – Callin bindings declare overriding by which a team definition may alter the behavior of base classes.

    - 12 -

    Abbildung 3: Beziehung zwischen Team, Rolle und Basis

    ([HE2005], Seite 6)

    13

  • Mit Hilfe dieser Bindungen kann in Object Teams aspektorientiertes Verhalten implementiert werden. So ver-

    ändert ein callin-Bindung das Verhalten der Basisinstanz, indem statt der Methode der Basis die Metho-de der Rolle ausgeführt wird. Hierzu muss die Basis nicht verändert werden, denn die Definition des Aufrufs

    erfolgt mit Hilfe eines bindings in der Team Klasse. Im Gegensatz dazu leitet ein callout-Binding einen Methodenaufruf einer Rolle an eine Methode der Basisklasse weiter.

    Nachdem nun die grundlegenden Konzepte der Object Teams Implementierung erläutert wurden, soll die

    konkrete Anwendung einer Team Klasse, also eine genauere Beschreibung der Ausprägungen der bindings

    zwischen Rollen- und Basisklassen in Abschnitt 4.2.2.erfolgen.

    4.2.2 Anwendung der Collaborations

    Das Schlüsselwort team zeigt bereits, dass eine größere Gruppe von Objekten eine Kollaboration bilden. Je-des Team kann hierbei beliebig viele Rollen beinhalten, welche in ihrer Kombination eine bestimmte Funktio-

    nalität zur Verfügung stellen.

    Diese Rollen werden von Basisklassen „gespielt“, welche durch das Schlüsselwort playedBy an die jeweili-ge Rolle angebunden sind. Die Basisklassen müssen also nicht verändert werden und auch nichts von ihrer

    Einbindung in das Team „wissen“.

    Weiterhin führt das Object Teams Modells den Begriff der Bindungen ein. Mit Hilfe von bindings kann aspekt-

    orientiertes Verhalten implementiert werden. Sie werden nicht durch ein Schlüsselwort eingeleitet, sondern

    über die Operatoren „->“ und „

  • Im Unterschied zu den bei AspectJ verwendeten Aspekten sind die bei Object Teams verwendeten Team-

    und Rollen-Klassen instantiierbar, d.h. Sie können als „normale“ Objekte verwendet werden und auch weite-

    re „normale“ Attribute und Methoden definieren. Mit Object Teams ist es also möglich Hierarchien von Kolla-

    borationen aufzubauen, wobei die Eigenschaften einzelner Teams polymorph veränderbar sind. Es lassen

    sich also wiederverwendbare Kollaborationen von Aspekten erstellen.

    Der folgende schematische Quelltextauszug verdeutlicht nochmals die Möglichkeiten der in den letzten Ab-

    sätzen erläuterten Struktur einer Team-Klasse.

    84 /* Hier wird die Team-Klasse definiert, welche die Rollen beinhaltet */ 85 public team class MyTeam [extends SuperTeam] { 86 87 /* Attribute des Teams */ 88 int counter = 0; 89 // ... 90 91 /* Methoden des Teams */ 92 void count() { 93 counter++; 94 } 95 // ... 96 97 98 /* Definition einer Rolle */ 99 class Role playedBy MyBasis { 100 101 /* Attribute der Rolle */ 102 private int myInt = 0; 103 104 /* Methoden der Rolle */ 105 void doSomethingBeforeBaseMethod() { /* ... */} 106 107 void doSomethingAferBaseMethod() { /* ... */} 108 109 void doSomethingInsteadOfBaseMethod() { /* ... */} 110 111 abstract useBaseMethod(); 112 113 /* Bindings der Rolle */ 114 /* call-in */ 115 doSomethingBeforeBaseMethod

  • 4.3 Fallbeispiel: Objektpersistenz (Aspectual Collaboration)

    An dieser Stelle soll nun das Beispiel aus den Kapiteln 2.2 und 3.3 fortgeführt werden. Erneut handelt es

    sich um das Speichern eines einfachen Objektes. Nach jedem Aufruf einer mit dem Präfix set beginnenden Methode eines Objektes soll eben dieses Objekt mit Hilfe des in Kapitel 2.2 eingeführten Persisters gespei-

    chert werden.

    Hierzu kommt in diesem Abschnitt eine Team-Klasse der „Aspectual Collaboration“-Implementierung Object

    Teams (siehe [ObjTeams]) zum Einsatz. Eine ab Zeile 164 definierte Rolle ObjectRole stellt mit Hilfe des Schlüsselwortes playedBy die Beziehung zu einem Basisobjekt vom Typ Foo her. Außerdem wird ab Zeile 147 auf gleiche Weise der Klasse PersisterImpl8 die PersisterRole zugewiesen. Das in Zeile 187 de-finierte callin–binding stellt weiterhin sicher, dass nach allen Aufrufen der Methode setBar(...) an ei-nem Objekt vom Typ Foo auch ein Aufruf der Methode ObjectRole.save() erfolgt. Diese Methode leitet den Aufruf zur PersisterRole weiter. Daraufhin wird über die abstrakte Methode PersisterRole.store() (Zeile 155) und das zugehörige callout-binding (Zeile 160) letztlich die eigentliche Speicherfunktionalität des zugeordneten Basisobjektes vom Typ PersisterImpl angesprochen.

    Der Zugriff auf ein Basisobjekt einer Rolle wird von Object Teams recht restriktiv gehandhabt. Nur unter be-

    stimmten Bedingungen (siehe Object Teams-Spezifikation) hat eine Rollenmethode über das Schlüsselwort

    base beschränkt Zugriff auf das zugeordnete Basisobjekt. Dies reicht für den hier betrachteten Anwendungs-

    fall nicht aus, da ja das Basisobjekt und nicht die Rolle gespeichert werden soll. Deshalb muss das Basisob-

    jekt vom Typ Foo der ObjectRole anderweitig bekannt gemacht werden. Der in den Zeilen 170-172 über-schriebene Standard lifting constructor stellt der ObjectRole während ihrer Instantiierung eine Referenz zu dem zugeordneten Basisobjekt zur Verfügung. Somit ist es nun jederzeit möglich auf das der ObjectRole zugeordnete Basisobjekt direkt zu zu greifen und dessen aktuellen Zustand zu speichern.

    128 package fallbeispiele.persistenz.ot; 129 130 import java.io.IOException; 131 import java.io.Serializable; 132 133 import fallbeispiele.persistenz.modul.Persister; 134 import fallbeispiele.persistenz.modul.PersisterImpl; 135 import fallbeispiele.persistenz.vo.Foo; 136 137 public team class PersistenzTeam { 138 139 private PersisterRole persisterRole; 140 141 // initialize the persister role during team instantiation 142 public PersistenzTeam(){ 143 persisterRole = 144 new PersisterRole((PersisterImpl)Persister.Factory.getInstance()); 145 } 146 147 public class PersisterRole playedBy PersisterImpl { 148

    8 Derzeit kann ObjectTeams nur Klassen aber keine Schnittstellen an Rollen binden. Daher wird die PersisterRole hier von der Klasse PersisterImpl und nicht von der Schnittstelle Persister „gespielt“.

    - 15 -16

  • 149 // override default lifting constructor to store 150 // the persister role instance as team property 151 PersisterRole(PersisterImpl aPersisterImpl){ 152 PersistenzTeam.this.persisterRole = this; 153 } 154 155 abstract public void store(String path, Serializable s) throws IOException; 156 157 // callout binding that maps the abstract store method of the 158 // PersisterRole to the concrete saveObject method of the related 159 // base class PersisterImpl 160 store -> saveObject; 161 162 } 163 164 public class ObjectRole playedBy Foo { 165 166 private Foo foo; 167 168 // override default lifting constructor to remember 169 // reference to related base object; 170 ObjectRole(Foo aFoo) { 171 foo = aFoo; 172 } 173 174 // stores the base object related to this role 175 void save() { 176 try { 177 PersistenzTeam.this.persisterRole.store( 178 "./" + foo.hashCode() + ".obj", (Serializable)foo); 179 System.out.println("Foo stored successfully!"); 180 } catch (IOException e) { 181 e.printStackTrace(); 182 } 183 } 184 185 // callin binding that calls saveFoo() after each invocation 186 // of the enlisted base methods on the base object 187 save

  • Jedes dieser drei Projekte erweitert die objektorientierte Sprache JAVA um Elemente, mit denen Aspekte

    modularisiert und Kollaborationen von zueinander in Beziehung stehenden Modulen und deren Zusammen-

    spiel definiert werden können. Um mit diesen Sprachelementen erweiterten Quellcode zu einem lauffähigen

    JAVA-Programm zu kompilieren wird jeweils ein eigener Compiler zur Verfügung gestellt. In der folgenden

    Tabelle 1 werden die Schlüsselworte der untersuchten Spracherweiterungen kurz gegenübergestellt.

    ACC CaesarJ ObjectTeamsKollaborationen collaboration Caesar Klassen cclass Teamklassen team

    Rollen participant Virtuelle Klasse

    (inner cclass)

    an ein team gebundene

    Klassen

    Querschnittsbelange aspectual, attach,

    export, provide

    AspectJ-Style Pointcuts

    und Advices

    callin/callout bindings,

    before, after, replace,

    get, set

    Basisklassenanbindung participant extends

    BasisKlasse

    Objektkomposition und

    Schnittstellen-

    implementierung

    Rollenklasse

    playedBy

    Basisklasse

    Tabelle 1: JAVA-Spracherweiterungen der unterschiedlichen AC-Implementierungen

    Die nächsten beiden Abschnitte beschäftigen sich mit dem aktuellen Entwicklungsstand der beiden Imple-

    mentierungen ACC und CaesarJ.

    4.4.1 Aspectual Collaboration

    Die Arbeit an der „Aspectual Collaboration“-Implementierung begann an der Northeastern University, Boston

    verhältnismäßig früh und bildete damit die Basis vieler anderer Forschungsarbeiten zu diesem Thema. Im

    Jahr 1998 erschien die erste grundlegende Arbeit hierzu von Mira Mezini und Karl Lieberherr ([MMKL98]). Im

    Rahmen der weiter oben schon erwähnten PhD-Thesis ([OV0404]) wurde dann der hier angesprochenen

    Aspectual Collaboration Compiler ACC prototypisch entwickelt. Im Gegensatz zu den Projekten CaesarJ und

    Object Teams wurde die Weiterentwicklung dieses Compilers allerdings nicht mehr aktiv fortgeführt, so dass

    sich dessen Dokumentation auf die erwähnte PhD-Thesis beschränkt.

    4.4.2 CaesarJ Projekt

    Ein weiteres Projekt, welches sich mit aspektorientierten Kollaborationen beschäftigt, ist das an der Techni-

    schen Universität Darmstadt voran getriebene Projekt CaesarJ ([CaesarJ]). Ähnlich dem Projekt Object-

    Teams ist es dem akademischen Umfeld weitgehend entwachsen und wird als Opensource-Projekt weiter-

    geführt. Bessere Modularität wird durch die Verwendung von Kollaboration-(Caesar-)Klassen (cclass) er-

    reicht, welche voneinander abgeleitet werden können. Innerhalb dieser Klassen werden sogenannte virtuelle

    Klassen definiert, denen bestimmte Rollen zugeordnet sind. Die Hierarchien der Caesar- und der „normalen“

    Java-Basisklassen ist strikt getrennt. Die Interaktion zwischen den mit bestimmten Rollen verbundenen virtu-

    ellen Klassen und den Basisklassen erfolgt ausschließlich über Objektkomposition und Schnittstellenimple-

    - 17 -18

  • mentierung. CaesarJ führt hierzu unter anderem einen neuen Kompositionsmechanismus ein. Caesar-Klas-

    sen könne mit Hilfe des &-Operators direkt kombiniert werden, wobei die resultierende Klasse dann die Ei-

    genschaften beider Basisklassen besitzt. Aspektorientierte Sprachkonzepte entsprechen weitgehend

    AspectJ ([ASPECTJ]). Neben dem Deployment zur Kompilierzeit kann CaesarJ Aspekte auch zur Laufzeit

    aktivieren bzw. deaktivieren. Dies erhöht die Flexibilität bei dessen Einsatz erheblich.

    4.5 Probleme

    Derzeitige Implementierungen welche sich mit aspektorientierten Kollaborationen beschäftigen lassen vor al-

    lem eins vermissen – den Nachweis der Alltagstauglichkeit in konkreten Industrieprojekte. Zumindest Object

    Teams wie auch CaesarJ wurden im akademischen Umfeld weit vorangebracht. Die Konzepte dieser beiden

    Implementierungen werden vom Bundesministerium für Forschung und Bildung im Rahmen des Forschungs-

    projektes TOPPrax ([TOPPrax]) für den Einsatz in der betriebliche Softwareentwicklung konsolidiert. Dabei

    gilt es die Schwachpunkte der existierenden Ansätze auszuräumen und deren Vorteile zu vereinen. Insbe-

    sondere soll umfassende Werkzeugunterstützung garantiert und der ökonomische Nutzen des aspektorien-

    tierten Ansatzes in größeren Projekten aufgezeigt werden.

    5 Zusammenfassung

    Das Ziel von neuen Konzepten in der Softwareentwicklung ist es, die Erstellung von immer komplexer wer-

    denden Softwaresystemen zu vereinfachen. Modulare Programmierung zerlegt hierzu das zu lösende Pro-

    blem in kleinere Probleme und schafft für die Teilprobleme Softwarebausteine, die sich zu einem Gesamt-

    system zusammensetzen lassen.

    Allerdings können mit Hilfe der modularen Programmierung keine das System quer schneidende Anforde-

    rungen modularisiert werden. Diese Anforderungen lassen sich zwar isoliert betrachten, aber es existiert kei-

    ne Möglichkeit, diese auch isoliert zu implementieren. Das recht junge Gebiet der aspektorientierten Pro-

    grammierung beschäftigt sich genau mit dieser Problematik, indem es eine zweite Ordnungsdimension

    schafft, in welcher sich diese quer schneidende Funktionalität kapseln und System übergreifend integrieren

    lässt.

    Problematisch bei Einsatz der Aspektorientierung ist der Verlust der Übersichtlichkeit im Quelltext. Bei Be-

    trachtung und Analyse des Codes müssen alle Aspekte betrachtet werden, da aus dem Code alleine nicht

    ersichtlich ist, welche Aspekte zur Laufzeit zur Anwendung kommen. Auch das Finden von Fehlern wird er-

    schwert, da Sprünge zwischen in Aspekten und in herkömmlichen Klassen implementierter Funktionalität er-

    folgen. Weiterhin wird durch die Verwendung von Aspekten nicht sichergestellt, dass die entwickelten Aspek-

    te auch wiederverwendbar sind, da sie speziell für eine bestimmte Problemstellung geschrieben werden.

    Das Modell der Aspectual Collaborations beschreibt die Zusammenarbeit von Objekten in einem bestimmten

    Kontext, indem die einzelnen Objekte eine bestimmte Rolle spielen. Dazu werden innerhalb einer Kollabora-

    tion genau diese Rollen und deren rollenspezifisches Verhalten definiert. Die Kollaboration definiert weiterhin

    - 18 -19

  • die Rollenklassen und verknüpft die Funktionalität der Rollen mit der Funktionalität der zugeordneten Basis-

    klassen.

    Auch wenn einige Implementierungen des Ansatzes der Aspectual Collaborations schon eine recht stabile

    Basis für industrielle Projekte bieten, ist die Verbreitung in dieser Art von Projekten bis jetzt noch nicht er-

    folgt.

    6 Literatur

    [HE2002] Stephan Herrmann: Object Teams: Improving Modularity for Crosscutting Collaborations,

    2002, http://www.objectteams.org/publications/NODe02.pdf

    [ASPECTJ] Eclipse - AspectJ Project, http://www.eclipse.org/aspectj/

    [ObjTeams] Object Teams, http://www.objectteams.org/

    [WPMP] Modulare Programmierung, http://de.wikipedia.org/wiki/Modulare_Programmierung

    [WA04] Informatik Vorlesung Wintersemester 2004, http://www.imn.htwk-

    leipzig.de/~waldmann/edu/ws04/informatik/folien/informatik/index.html

    [01853] Friedrich Steimann, Moderne Programmiertechniken und -methoden, 2005

    [WPCCC] Cross-Cutting Concern, http://de.wikipedia.org/wiki/Cross-Cutting_Concern

    [WPAOP] Aspektorientierte Programmierung, http://de.wikipedia.org/wiki/AOP

    [MO2003] Marco Mosconi: Modularisierung und Adaptierung von Komponenteninteraktionen mit Object

    Teams und dem CORBA Komponentenmodell, 2003, , TU Berlin, Diplomarbeit

    [MMKL98] Mira Mezini, KarlLieberherr: Adaptive Plug-and-Play Components for Evolutionary Software

    Development, , ftp://ftp.ccs.neu.edu/pub/people/lieber/appcs.pdf

    [LiLoMe99] Karl Liebherr, David Lorenz, Mira Mezini: Programming with Aspectual Components, 1999,

    http://www.ccs.neu.edu/research/demeter/papers/aspectual-comps/aspectual.ps

    [HE2005] Stephan Herrmann: Roles in a Context, 2005,

    http://www.objectteams.org/publications/ROLES05.pdf

    [OV0404] Johan Ovlinger: Combining Aspects and Modules, April 2004, College of Computer Science,

    Northeastern University, Boston, http://www.ccs.neu.edu/home/johan/research/thesis.pdf

    [OVACC] AC Compiler, http://www.ccs.neu.edu/home/johan/research/acc/index.html

    [CaesarJ] CaesarJ Project, http://www.caesarj.org

    [TOPPrax] Aspektorientierte Programmierung für die Praxis, http://www.topprax.de

    - 19 -20

  • Komponentenbasierte Programmierung

    Komponenten in UML 2.0

    FernUniversität in Hagen

    Fachbereich Informatik Lehrgebiet Programmiersysteme

    Seminar 1908 im Sommersemester 2006 Betreuer: Prof. Dr. Steimann Bearbeiter: Lars Greiffenhagen

    Peter Stumfol

    21

  • Inhalt

    1 ÜBERBLICK ÜBER DIE ARBEIT 3

    2 EINFÜHRUNG 4

    2.1 DER ALLGEMEINE KOMPONENTENBEGRIFF 4 2.2 UML 2.0 4 2.2.1 DIE ENTWICKLUNG DER UML 4 2.2.2 WAS IST DIE UML? 5 2.2.3 WAS IST DIE UML NICHT? 5 2.3 EINORDNUNG DER KOMPONENTE IN DIE UML 5

    3 DARSTELLUNG EINER KOMPONENTE IN UML 7

    3.1 COMPONENT 7 3.2 INTERFACE 8 3.3 PORTS 9 3.4 PARTS 10 3.5 CONNECTORS 11 3.6 COMPONENT ARTIFACTS 12 3.7 COMPONENT DIAGRAM 12

    4 BEISPIEL 14

    4.1 PROBLEMSTELLUNG 14 4.2 SYSTEMENTWURF 14 4.3 DARSTELLUNG DER KOMPONENTE MIT SCHNITTSTELLEN 15 4.4 KOMPONENTENDIAGRAMME 15 4.5 EXEMPLARISCHE CODIERUNG IN JAVA 18

    5 ZUSAMMENFASSUNG 19

    6 LITERATURVERZEICHNIS 20

    22

  • Komponenten in UML 2.0

    3

    1 Überblick über die Arbeit Die vorliegende Arbeit beschreibt die Modellierung von Komponenten mit der UML Version 2.0. In dieser Arbeit werden alle Begriffe, die in diesem Zusammenhang auftreten, näher erläutert und deren grafische Darstellung demonstriert. Kapitel 2 führt zunächst in die wesentlichen Thematiken ein. Dabei wird, basierend auf bisherige Seminararbeiten, der Begriff der Komponente nochmals kurz dargestellt. Anschließend werden wir den Begriff UML näher beleuchten: was ist die UML, was ist sie nicht? Wer steckt hinter der UML und wie hat sich die UML entwickelt? Den Abschluss der Einführung bilden die Einordnung der Komponente, und die in diesem Zusammenhang verwendeten Notationselemente, in die UML. Der Kern dieser Arbeit findet sich in Kapitel 3. Dieses Kapitel erläutert nacheinander die wichtigsten Begriffe für die Modellierung von Komponenten mittels UML. Jedem der Begriffe „component“, „interface“, „ports“, „parts“, „connectors“ „component artifacts“ und „component diagram“, ist ein eigenes Unterkapitel gewidmet. Die Vorgehensweise dabei ist immer dieselbe: zunächst wird der Begriff erläutert, danach wird die grafische Notation in UML dargestellt und wenn sinnvoll, schließt ein kleines Beispiel das entsprechende Unterkapitel ab. Kapitel 4 vertieft im Wesentlichen die Thematik aus dem vorangegangenen Kapitel anhand eines größeren Beispiels. Zunächst erfolgt eine informelle Einführung in das Beispiel. Anschließend wird die Modellierung schrittweise verfeinert. Abschluss des Beispiels ist eine exemplarische Implementierung in Java. Kapitel 5 fasst abschließend die Arbeit zusammen und gibt einen kurzen Ausblick.

    23

  • Komponenten in UML 2.0

    4

    2 Einführung

    2.1 Der allgemeine Komponentenbegriff Die Idee bzw. Motivation der Komponente ist es, ein Softwaresystem, analog zu anderen Ingenieursdisziplinen, aus vorhandenen Bausteinen zusammenzubauen. Hinter diesen Bausteinen verbirgt sich der Begriff der Komponente. Eine interessante Metapher ist die Legostein-Metapher: die einzelnen Lego-Bausteine (=Komponenten) werden vom Spielzeughersteller Lego (=Komponentenentwickler) produziert, die Bauwerke (=Anwendungssysteme) werden vom Spieler (=Anwendungsentwickler) hergestellt. An Komponenten sind hohe Erwartungen gestellt:

    • Zum einen sollen Spezialisten Komponenten entwickeln und zum anderen sollen Anwendungsentwickler anhand vorhandener Komponenten Anwendungen zusammenbauen können. Ein Anwendungssystem versteht sich somit als eine Komposition von Komponenten.

    • Der Einsatz einer Komponente soll unabhängig vom Anwendungskontext sein. Dies hat zur Folge, dass zur Entwicklungszeit der zukünftige Anwendungskontext nicht bekannt ist.

    Technisch betrachtet bietet eine Komponente ihre Dienste über eine Schnittstelle an und kann selbst weitere Komponenten nutzen. Obwohl Komponenten viele Gemeinsamkeiten mit Objekten aufweisen, sieht man die komponentenorientierte Programmierung als ein eigenes Paradigma: Komponenten sind größer, stellen ihre Funktionalität dem Anwender gegenüber in den Vordergrund und müssen nicht zwangsläufig in einer objektorientierten Sprache implementiert sein. Die Regeln, wie Komponenten definiert, implementiert und ausgeliefert werden sollen, legt das Komponentenmodell fest. Verbreitete Komponentenmodelle sind Enterprise Java Beans (EJB), Distributed Component Object Model (DCOM) und CORBA Component Model. Zusammengefasst stellen Komponenten über ihre klar definierten Schnittstellen Dienste gegenüber Dritten bereit. Die Schnittstelle regelt dabei, wie auf die Komponente zugegriffen werden kann und beschreibt das Verhalten. Konkrete Implementierungen von Komponenten sollen durch andere austauschbar sein, ohne dass Änderungen am System nötig sind.

    2.2 UML 2.0

    2.2.1 Die Entwicklung der UML Ihren Ursprung findet die UML in den frühen 90er Jahren. In dieser Zeit, die objektorientierte Programmierung findet gerade ihre Akzeptanz in der Industrie, fanden wahrlich "Methodenkriege" statt. Zunächst einmal versuchten J. Rumbaugh und G. Booch Methoden und Notationen zu vereinigen:

    • OOA (object oriented analysis) 24

  • Komponenten in UML 2.0

    5

    • OOD (object oriented design) • OMT (object modelling technique)

    Daraus entstand die Unified Method v0.8. Kurze Zeit später gesellt sich I. Jacobson hinzu. Diese drei Personen werden bis heute die "3 Amigos" genannt. Die Bemühungen, alles zu vereinheitlichen wurde nun auf die Notation beschränkt. Ferner wurde die statische und dynamische Modellierung integriert. Die Ergebnisse finden sich in der UML (Unified Modelling Language) v0.9ff wieder. 1997 entstand die Version UML 1.0. Mit dieser Version begannen die Aktivitäten zur Standardisierung. Danach wurde die UML stetig weiter entwickelt, um diese auch in der Industrie einsetzen zu können. Ab der Version 1.3 übernimmt die Object Management Group, kurz OMG, das Copyright und sieht sich als die Hüterin des UML-Standards. Seit dieser Version ist UML offiziell mit der Expansion OMG Unified Modelling Language belegt. Die OMG ist ein Gremium mit ca. 800 namhaften Mitgliedern aller relevanten Marktvertreter (IBM, HP, Oracle, Microsoft, Daimler-Chrysler,...). Die aktuelle Version UML 2.0 aus dem Jahre 2004 erfuhr die größte Änderung. Hier flossen die Erfahrungen der ersten Versionen ein. Unter anderem wurde die Notation und das Metamodell der Komponente geändert: Die Komponente ist nun eine Spezialisierung von Classifier und kann deshalb alle Arten von Strukturmerkmalen haben. Strukturmerkmale sind Attribute, Operationen, Generalisierungen und Assoziationen. Auch das Komponenten-diagramm findet zum ersten Mal Berücksichtigung. In der Industrie wird der Begriff der UML oft falsch interpretiert. Aus diesem Grund folgt hier eine kurze Ausführung über das, was die UML ist und was sie nicht ist.

    2.2.2 Was ist die UML? Die UML dient zur Modellierung, Dokumentation, Spezifizierung und Visualisierung komplexer Softwaresysteme, unabhängig von irgendwelchen Anwendungssystemen. Sie liefert die Notationselemente für die statischen und dynamischen Modelle von Analyse, Design und Architektur. Die UML unterstützt insbesondere die objektorientierten Vorgehensweisen.

    2.2.3 Was ist die UML nicht? Aufgrund des schnellen Fortschrittes und der zunehmenden Komplexität von Software wird die UML nie vollständig und abgeschlossen sein. Auch ist sie keine Programmiersprache und auch keine rein formale Sprache. Gerne wird die UML als Methode oder Vorgehensmodell gesehen, auch das ist schlichtweg falsch. Sie ist auch kein Allheilmittel, vor allem ist sie kein vollständiger Ersatz für Textbeschreibungen.

    2.3 Einordnung der Komponente in die UML Komponenten werden in der UML in Form von Komponentendiagrammen dargestellt. Ein Komponentendiagramm stellt dar, wie ein System strukturiert ist und wie diese Strukturen erzeugt werden. Das Komponentendiagramm lässt sich innerhalb der UML den Strukturdiagrammen zuordnen. Das Komponentendiagramm wurde ab UML 2.0 neu eingeführt. Selbiges gilt für das Kompositionsdiagramm. Dieses wird vor allem dann eingesetzt, wenn man ein System auf Architekturebene darstellen will. Aus diesem Grund wird das Kompositionsdiagramm auch oft als Architekturdiagramm bezeichnet. Das Kompositionsdiagramm führt Elemente ein, welche auch innerhalb der Komponenten bzw. eines Komponentendiagramms eingesetzt werden. Auch Elemente des Klassendiagramms werden bei der Darstellung von Komponenten verwendet: zum einen die Klasse und zum anderen die Schnittstelle.

    25

  • Komponenten in UML 2.0

    6

    Das Komponentendiagramm führt folgende Notationselemente ein: • component: Eine Komponente ist ein modularer Systemteil, der seinen Inhalt

    transparent kapselt und so dem Anwender gegenüber verbirgt. • artifact: Ein Artefakt stellt eine physische Informationseinheit in Form einer Datei

    dar. Hierbei handelt es sich um ausführbare Dateien, Dokumente, Daten etc. Konkretisiert werden die Artefakte durch neu eingeführte Stereotypen.

    • associations: Im Zusammenhang mit den Artefakten werden folgende Beziehungen durch Stereotypen verwendet:

    o - Realisierungsbeziehung o - Implementierungsbeziehung o - Verwendungsbeziehung

    Aus dem Kompositionsdiagramm werden folgende Notationselemente verwendet:

    • ports sind benannte Zugänge einer Komponente. Ports bündeln die Schnittstellen zu einer Einheit. Die zugrunde liegende Idee ist, dass die Komponente nur noch über Ports erreichbar ist.

    • parts werden verwendet, um die interne Struktur eines Classifiers darzustellen. Ein Part repräsentiert eine Menge von Ausprägungen, die zu einer Ausprägung des umgebenen Classifiers gehört. Die UML kennt 3 Arten von Ausprägungen: Das Objekt als Ausprägung einer Klasse, den Link als Ausprägung einer Assoziation und den Wert eines einfachen Attributes oder einfachen Objektes mit genau einem atomaren Wert. Parts werden meist durch eine Komposition mit dem zugehörigen Classifier verbunden.

    • connectors werden oft auch in Kollaborationsdiagrammen oder bei der internen Beschreibung einer Klasse oder Komponente verwendet. Ein Konnektor beschreibt eine Kommunikationsverbindung zwischen zwei sog. verbindbaren Elementen (connectable elements). Verbindbare Elemente in der UML sind u.a. Ports und Parts.

    Weitere wichtige Elemente zur Darstellung von Komponenten sind in den Klassendiagrammen zu finden:

    • class: Klassen stellen das zentrale Element eines Klassendiagramms dar. Eine Klasse beschreibt eine Menge von Objekten mit gemeinsamer Semantik, gemeinsamen Eigenschaften und gemeinsamen Verhalten.

    • interface: Auf Komponenten kann nur über die Komponentenschnittstelle zugegriffen werden. Eine Schnittstelle beschreibt eine Menge von Operationen, Merkmalen und Verpflichtungen. Unter einer Verpflichtung versteht man die Vor- und Nachbedingungen und die semantischen Gegebenheiten die mit der der Schnittstelle assoziiert sind. Da Schnittstellen zur Definition von abstrakten Eigenschaften verwendet werden, müssen diese von Klassen realisiert bzw. implementiert werden. Je nach Verwendung einer Schnittstelle ist folgende Unterscheidung wichtig:

    o Unter provided interface versteht man eine Schnittstelle, die eine Klasse oder

    Komponente anbietet. In diesem Fall fungiert die Klasse oder Komponente als Dienstleister oder Server.

    o Ein required interface stellt eine benötigte Schnittstelle dar. Die Klassen oder Komponenten, die diese Schnittstelle verwenden, treten hierbei als Dienstnutzer oder Client auf.

    26

  • Komponenten in UML 2.0

    7

    3 Darstellung einer Komponente in UML In diesem Kapitel werden die Begriffe „Component“, „Interface“, „Port“, „Part“, „Connector“ und „Component artifact“ in den jeweiligen Abschnitten zunächst erläutert sowie deren Notation in der UML anhand von Beispielen gezeigt und verfestigt. Der Begriff „Component diagram“ wird im letzten Unterabschnitt erläutert und fasst alle bisher diskutierten Begriffe in einer Darstellung zusammen. Hierdurch wird ein Gesamteindruck vermittelt, der nahezu alle zuvor erwähnten Elemente in einem Diagramm vereint. Die Notation orientiert sich jeweils an den Ausführungen in [BoJaRu04], [OMG05] und [Oester04].

    3.1 Component Eine Komponente (engl. component) beschreibt eine austauschbare Softwareeinheit mit definierten Schnittstellen und eigener Identität als Teil eines logischen oder physischen Systems. Komponenten bilden Einheiten hoher fachlicher Kohärenz. Eine Komponente definiert eine Art Namensraum für die in ihr enthaltenen Elemente (z.B. Design Elemente, Anwendungsfälle, Interaktionen). Wie in [Oester04] beschrieben wird, sind Komponenten analog zu Klassen instanziierbar und kapseln komplexes Verhalten, das hinter einer Reihe von Schnittstellen verborgen wird. Durch die Trennung von Schnittstelle und Implementierung können Komponenten, wie bereits in Abschnitt 2.1 erwähnt, in Form von Bausteinen in unterschiedliche Systeme einfach „eingesteckt“ werden, sofern die betreffenden Schnittstellen kompatibel sind. Diese Art der Verwendung von Komponenten fördert die Modularität und steigert die Wiederverwendbarkeit von Software. Komponenten verfolgen im Wesentlichen zwei Aspekte: zum einen definieren sie das äußere Erscheinungsbild der Komponente in Form von Interfaces (Abschnitt 3.2) und zum anderen implementieren sie eine bestimmte Funktionalität, die von der Komponente unterstützt bzw. bereitgestellt wird. Komponenten fassen Klassen oder Subkomponenten zusammen, die eine hohe fachliche Kohärenz haben. Die Implementierung einer Komponente wird durch das Zusammenspiel mehrerer sog. Parts (Abschnitt 3.4) oder Subkomponenten realisiert, die den internen Aufbau einer Komponente bilden. Operationen, die nach außen hin sichtbar sind, werden durch Interfaces modelliert. Interfaces beschreiben die Funktionalität, die von einer Komponente angeboten wird. Wie in Abschnitt 3.2 beschrieben wird, gibt es zwei unterschiedliche Arten von Interfaces: anbietende (provided) und genutzte (required) Interfaces. Mehrere Interfaces können dabei von sog. Ports (Abschnitt 3.3) zusammengefasst werden. Die interne „Verdrahtung“ einer Komponente wird durch sog. Connectors (Abschnitt 3.5) realisiert. Eine Komponente kann z.B. mehrere Subkomponenten beinhalten, die mittels Konnektoren über Ports miteinander verbunden sind. Eine Subkomponente weiß dabei nichts über die Existenz oder gar den internen Aufbau anderer Subkomponenten. Die Kommunikation zwischen Komponenten läuft dabei stets über deren Ports. Bestimmte Komponenten beinhalten sog. Artefakte (Abschnitt 3.6), die Bestandteil des Systems sind und aus physischen Elementen wie z.B. Skripten, Dateien, Hypertext Elemente etc. bestehen können. Eine Komponente wird in der UML als Rechteck notiert und mit dem Stereotyp gekennzeichnet. Anstatt des Stereotyps kann als visuelles Icon ein Rechteck mit zwei kleinen auf dem linken Rand sitzenden Rechtecken verwendet werden. Innerhalb der

    27

  • Komponenten in UML 2.0

    8

    Komponente wird der jeweilige Name der Komponente und ggf. ihr Typ beschrieben (Abbildung 3-1).

    Abbildung 3-1: Notationsformen für Komponenten

    3.2 Interface Wie bereits in den Abschnitten 2.1 und 3.1 erwähnt, sind Komponenten so konzipiert, dass diese in Form von Modulen oder Bausteinen in unterschiedlichen Softwaresystemen wieder verwendet werden können. Hierzu wird die jeweilige Komponente in ein bestehendes System „eingesteckt“ bzw. integriert. Damit dies funktioniert, benötigt die Komponente eine Art „Stecker“, um mit dem System, in das sie integriert wird, kommunizieren zu können. Dieser „Stecker“ wird als Schnittstelle (engl. interface) bezeichnet und dient dem Austausch von Nachrichten zwischen Komponente und Umgebung. Eine Komponente kann dabei mehrere Interfaces besitzen. Das System, das die Komponente verwendet, hat seinerseits ebenfalls eine oder mehrere Interfaces. Wichtig ist hierbei, dass beide Interfaces zueinander kompatibel sind, um den korrekten Nachrichtenaustausch zu gewährleisten. Interfaces dienen also einerseits der Kommunikation zwischen Komponente und externer Außenwelt und andererseits der Kommunikation zwischen Komponenten untereinander. Mit Hilfe von Interfaces kann z.B. von außen auf die Komponente zugegriffen werden. Interfaces machen somit einen Teil der Funktionalität nach außen hin sichtbar. Im Wesentlichen wird zwischen zwei Arten von Interfaces unterschieden: sog. provided Interfaces (anbietende Interfaces) werden von einer Komponente angeboten und können von anderen Komponenten oder Modellelementen verwendet werden. In diesem Fall agiert die Komponente als Server, der seine Dienste einem Client bzw. einer anderen Komponente zur Verfügung stellt. Die zweite Art von Interfaces ist das sog. required Interface (benötigtes Interface). Besitzt eine Komponente ein required Interface, so benötigt sie ein solches Interface z.B. von einer anderen Komponente, um korrekt zu funktionieren. Hier entspricht die Komponente einem Client, die einen oder mehrere Dienste einer anderen Komponente nutzt. Zu beachten ist hierbei, dass die Abhängigkeit zwischen Komponenten möglichst gering ausfallen sollte, um die universelle Verwendung einer Komponente zu gewährleisten. Je geringer die Abhängigkeit von Komponenten untereinander ist, desto flexibler lassen sich diese in vorhandene Umgebungen integrieren. Diese Art der Abhängigkeit wird auch schwache Kopplung genannt. Abbildung 3-2 zeigt eine Notationsform für Komponenten und deren Interfaces. Interfaces können, ähnlich wie in einem Klassendiagramm, in einem Abschnitt des Rechtecks notiert werden. Die Schlüsselwörter „provided“ und „required“ dienen hierbei der Unterscheidung der verschiedenen Interfacetypen. Die gebräuchlichste Notation ist die symbolisierte Darstellung (Abbildung 3-2 rechts): hier werden anbietende (provided) Interfaces als Kreis, der durch eine Linie an der Komponente befestigt ist, dargestellt. Diese Art der Notation wird in der Literatur häufig auch als „Lollipop“ bezeichnet. Für benötigte (required) Interfaces wird ein Halbkreis verwendet.

    28

  • Komponenten in UML 2.0

    9

    Abbildung 3-2: Notationsformen für Komponenten und Interfaces (Quelle: [BoJaRu04])

    Für die explizite Darstellung (Abbildung 3-3) werden Interfaces in Form von Klassen modelliert. Die Beziehungen zwischen Komponente und Interfaces werden durch die jeweiligen Abhängigkeitspfeile modelliert: anbietende Interfaces werden durch eine Realisierungsbeziehung (gestrichelte Linie mit geschlossener Pfeilspitze), genutzte Interfaces durch eine Benutzt-Beziehung (gestrichelte Linie mit offener Pfeilspitze) symbolisiert. Wie aus Abbildung 3-3 ersichtlich, kann hier die Stereotypbezeichnung für die Realisierungsbeziehung entfallen. Die Benutzt-Beziehung wird laut [BoJaRu04] und [OMG05] hingegen mittels explizit stereotypisiert.

    Abbildung 3-3: Explizite Darstellung von Komponenten und Interfaces (Quelle: [BoJaRu04])

    Zur besseren Strukturierung von Interfaces können diese, wie in Abschnitt 3.3 noch beschrieben wird, zu sog. Ports zusammengefasst werden. Die Kommunikation mit der Außenwelt findet dann über diese Ports statt.

    3.3 Ports Ein Port stellt einen Verbindungspunkt zwischen einer Komponente und deren Umgebung dar. Ports können Interfaces mit einem ähnlichen Kontext bündeln oder lediglich ein einzelnes Interface über einen Port der Umgebung zur Verfügung stellen. Es können sowohl provided als auch required Interfaces an einem Port liegen. Wie auch Interfaces, verbergen Ports die interne Struktur einer Komponente vor der Außenwelt. Die Außenwelt kommuniziert lediglich über die entsprechenden Ports mit der Komponente. Auf der anderen Seite findet die Kommunikation seitens der Komponente mit der Außenwelt ebenfalls nur über die existierenden Ports statt. Nachrichten an eine Komponente mit Ports werden dann direkt an den entsprechenden Port geschickt. Die Implementierung der Komponente entscheidet dann, an welchem Port Nachrichten empfangen werden und von welchem Port aus Nachrichten gesendet werden. Es gibt zwei Arten von Ports: ein sog. behavior port ist ein Port, dessen Implementierung direkt in der Komponente realisiert wird, die diesen Port bereitstellt. Ein sog. delegation port leitet die Anfragen bzw. die Nachrichten an einen Port einer Subkomponente weiter, die für dessen Implementierung verantwortlich ist. Der Typ eines Ports wird durch seine angebotenen (provided) und benötigten (required) Interfaces festgelegt. Ein Port kann alternativ als Interface oder Klasse typisiert sein. Die Realisierung eines Ports erfolgt durch ein explizites Objekt, das nachfolgend als „interaction point object“ bezeichnet wird. Bei diesem Objekt muss es sich um eine Instanz derjenigen Klasse handeln, die das provided Interface des entsprechenden Ports realisiert. Wird der Port

    29

  • Komponenten in UML 2.0

    10

    durch ein Interface typisiert, so realisiert die Klasse, die das interaction point object typisiert, das Interface. Wenn der Port mit einer Klasse typisiert wird, ist das interaction point object eine Instanz dieser Klasse. Die Existenz von Ports hängt unmittelbar mit der Lebensdauer der jeweiligen Komponente zusammen: beim Instanziieren einer Komponente werden die Ports erzeugt und beim Zerstören der Komponente werden auch deren Ports zerstört. Ports von internen Parts können entweder mit Ports anderer interner Parts oder aber mit delegation ports der umgebenen Komponente verbunden sein. Wichtig ist hierbei die Kompatibilität der jeweiligen Ports. In Bezug auf den Typ eines Ports werden hier zwei Arten der Verbindung unterschieden:

    1. Ist ein interner Port mit einem delegation port verbunden, so müssen beide Ports vom selben Typ sein. Dies ergibt sich daraus, dass z.B. eine Anfrage an einem delegation port dieselbe Anfrage an den entsprechenden internen Port darstellt.

    2. Sind zwei interne Ports mit einander verbunden, so muss der Typ beider Ports gegensätzlich sein, da eine Anfrage an einen Port ein Service des entsprechenden Gegenübers darstellt. Im einfachsten Fall gleicht das provided Interface des einen dem required Interface des anderen.

    In der UML werden Ports in Form von kleinen Quadraten notiert, die auf den Außenkanten einer Komponente sitzen. Nach außen hin können zusätzlich die jeweiligen Interfaces notiert werden. Abbildung 3-4 zeigt diese Art der Darstellung in Verbindung mit einer Komponente, die zwei Subkomponenten beinhaltet. In diesem Zusammenhang wird nochmals der Unterschied zwischen einem behavior port und einem delegation port deutlich. Letzterer leitet die Nachrichten lediglich an eine Subkomponente weiter, die ihrerseits für die Implementierung der Interfaces verantwortlich ist, während die Implementierung eines behavior ports direkt in der Hauptkomponente realisiert wird. In der Abbildung ist dies durch ein Rechteck mit abgerundeten Kanten dargestellt.

    Abbildung 3-4: Kommunikation zwischen Komponenten und Umgebung mittels Ports

    3.4 Parts Ein Part beschreibt die Rolle, die eine Instanz bzgl. eines bestimmten Classifiers spielt. Parts besitzen einen Namen, eine Multiplizität und einen Typ. Die Multiplizität gibt an, wie viele Instanzen dieser Klasse innerhalb der Komponente existieren. Jede Instanz wird hierbei als separates Modul betrachtet. Parts können einen Typ haben, der von dem Typ desjenigen Objekts abhängig ist, das die entsprechende Rolle beschreibt. Es kann mehrere Parts vom selben Typ geben. Jeder dieser Parts besitzt dabei unterschiedliche Beziehungen zu den

    Subkomponente 1 Subkomponente 2 delegation port

    behavior port

    delegation port

    behavior port

    30

  • Komponenten in UML 2.0

    11

    anderen Parts. Parts sind keine Instanzen, beschreiben aber alle Instanzen, die zu dem jeweiligen Part gebündelt sind.

    Abbildung 3-5: UML-Notation für Parts

    In der UML-Notation werden Parts als Rechtecke innerhalb der Komponente dargestellt. Sie können in der rechten oberen Ecke eine Angabe zur Multiplizität enthalten. Die Multiplizität kann alternativ auch hinter dem Namen des Elements in eckigen Klammern gesetzt werden. Abbildung 3-5 zeigt beide Varianten der Notation. Wird hingegen keine Multiplizität angegeben, gibt es nur eine einzige Instanz der Parts.

    3.5 Connectors Ein Konnektor (engl. connector) verbindet zwei Parts miteinander, um Nachrichten über deren Ports auszutauschen. Wird eine Nachricht von einem Port gesendet, so wird diese an einem anderen Port empfangen. Die Ports müssen hierbei vom selben Typ sein (siehe Abschnitt 3.3). Ein Konnektor, der den internen Port einer Komponente mit dem externen Port einer in ihr enthaltenen Subkomponente verbindet, wird als delegation connector bezeichnet. Gleiches gilt für die Verbindung zwischen dem externen Port einer Subkomponente und dem internen Port der umgebenen Komponente. In beiden Fällen werden die Informationen lediglich an eine andere Komponente weitergeleitet (delegiert). Konnektoren, die z.B. zwei Subkomponenten über deren Ports miteinander verbinden, heißen assembly connector. Konnektoren werden analog zu einer Assoziation durch eine Linie von einem Port zu einem anderen dargestellt. Die Richtung des Informationsflusses wird hierbei durch eine offene Pfeilspitze signalisiert.

    Abbildung 3-6: Beispiel für einen delegation connector (Quelle: [OMG05])

    Abbildung 3-6 zeigt anhand eines Beispiels die UML-Notation für einen delegation connector. Hier werden die Nachrichten über den Port OrderEntry an der Komponentengrenze entgegengenommen und an die entsprechenden Parts (hier:

    3 Part A

    Part A [3]

    31

  • Komponenten in UML 2.0

    12

    OrderHeader und LineItem) weitergeleitet. Die Verbindung zwischen LineItem und dem Port Person ist ebenfalls durch einen delegation connector spezifiziert. Assembly connectors werden ähnlich wie Interfaces mit Hilfe von ineinander greifenden Kreisen und Halbkreisen dargestellt. Abbildung 3-8 zeigt diese Art der Notation zwischen den Komponenten Order und Product sowie Order und Customer.

    3.6 Component artifacts Zunächst wird hier der Begriff des Knotens (engl. node) erläutert. Nach [Oester04] ist ein Knoten eine zur Laufzeit physisch vorhandene Einheit, die über Rechenleistung und Speicher verfügt (Hardware). In einem sog. Verteilungsdiagramm wird die Verteilung von Hard- und Software dargestellt, sprich: welche Software läuft auf welcher Hardware (Knoten). Ein Artefakt (engl. artifact) entspricht einer physischen Information (z.B. einem Programm), das während eines Softwareentwicklungsprozesses erstellt wurde und anschließend auf einem bestimmten Knoten ausgeführt wird. Hierzu gehören vor allem Dateien vom Typ *.exe, *.dll oder *.jar. Zwischen Komponenten und Artefakten kann eine sog. Manifest-Beziehung bestehen. Eine Manifest-Beziehung beschreibt die Beziehung zwischen einem Element des Modells (z.B. einer Komponente) und einem Artefakt, das dieses Element implementiert. Zu beachten ist, dass ein Artefakt mehrere Modellelemente implementieren und umgekehrt ein Modellelement von mehreren Artefakten implementiert werden kann. Man spricht daher von einer m:n-Beziehung.

    Abbildung 3-7: Manifest-Beziehung zwischen Artefakt und Komponente (Quelle: [BoJaRu04])

    Abbildung 3-7 zeigt beispielhaft eine Manifest-Beziehung zwischen einem Artefakt und einer Komponente. Artefakte werden in Form eines Rechtecks mit dem Stereotyp und dem Namen des Artefakts (hier: PurchaseOrder.jar) gekennzeichnet. Nach [ChoSch04] kann der Stereotyp weiter konkretisiert werden. Mögliche Stereotypen sind demnach „executable“ für ein ausführbares Programm, „library“ für eine dynamische oder statische Bibliothek, „script“ für einen zur Laufzeit interpretierten Programmtext, „page“ für eine einzelne Webseite und „file“ für eine gewöhnliche Datei. Die Manifest-Beziehung wird in der UML-Notation durch eine gestrichelte Linie mit einer offenen Pfeilspitze vom Artefakt zur Komponente hin symbolisiert. Ein Knoten ist in Form eines Quaders dargestellt. Knoten, die miteinander kommunizieren, werden durch Assoziationslinien miteinander verbunden.

    3.7 Component diagram Ein Komponentendiagramm (engl. component diagram) stellt die interne Struktur sowie die Gruppierung von Schnittstellen einer Komponente dar. Diese Art von Diagrammen, die auch als Kompositionsstrukturdiagramme bezeichnet werden (vgl. [Oester04]), zeigen, aus welchen Einzelteilen (z.B. Parts oder Subkomponenten) sich eine Komponente zusammensetzt. Ferner wird durch ein solches Diagramm deutlich, wie die einzelnen Teile zueinander in Beziehung stehen, welche Schnittstellen die Komponente nach außen anbietet und welche internen Teile mit diesen Schnittstellen verbunden sind. Die jeweiligen

    32

  • Komponenten in UML 2.0

    13

    Beziehungen der Teile untereinander werden über entsprechende Abhängigkeitspfeile dargestellt, die jeweils anbietende und genutzte Interfaces miteinander verbinden. Abbildung 3-8 zeigt ein Beispiel für ein Komponentendiagramm. Die Komponente Store besteht hierbei aus den Teilen (hier: Komponenten) Order, Customer und Product. Gut zu erkennen sind hier die Ports an den Außengrenzen der Komponente, die wiederum einige der Ports der Subkomponenten direkt „verdrahten“ und somit deren Funktionalität mittels eines „delegation connectors“ (Abschnitt 3.5) nach außen weiterleiten. Darüber hinaus sind die Beziehungen der einzelnen Subkomponenten untereinander zu erkennen, deren Kommunikation über die jeweiligen Interfaces Person und OrderableItem stattfindet. Von außen kann die Kommunikation mit der Komponente Store über die Ports OrderEntry (provided interface) und Account (required interface) stattfinden.

    Abbildung 3-8: Notation von Komponentendiagrammen (Quelle: [OMG05])

    33

  • Komponenten in UML 2.0

    14

    4 Beispiel

    4.1 Problemstellung Eine Hotelkette beauftragt eine Softwarefirma ein Reservierungssystem zu entwickeln. Kunden sollen von einem Webbrowser aus die Verfügbarkeit von Zimmern ermitteln können. Ist ein Zimmer verfügbar, so kann dieses vom Kunden unter Angabe seiner Kreditkarte reserviert werden. Das zu entwickelnde System soll das bereits vorhandene interne Reservierungssystem und die verwendete Datenbank nutzen. Ein bereits existierender Zugang zu einer Autorisierungsstelle für die Kreditkarteninformationen soll ebenfalls verwendet werden.

    4.2 Systementwurf Da das zu entwickelnde System sehr komplex ist, empfiehlt es sich zunächst einmal die Architektur des Systems zu betrachten. Dazu wird das System in eine 3-Schichten Architektur nach [SixWin06] zerlegt:

    • Externe Schnittstelle (View) ist für die Benutzerinteraktion verantwortlich • Anwendungskern (Controller) ist für die Logik verantwortlich • Datenhaltung (Model) ist für die Sicherung der Daten zuständig

    Jede dieser drei Schichten wird als separates Subsystem modelliert. Das Gesamtsystem „Hotel Reservation“ setzt sich aus den drei Subsystemen „Web Presentation“ (View), „Reservation Business Logic“ (Controller) und „Persistent Store (DB)“ (Model) zusammen. Abbildung 4-1 zeigt das Gesamtsystem als eine Aggregation der verwendeten Subsysteme. Jedes dieser Subsysteme wird in einem nächsten Schritt als Komponente entworfen.

    Abbildung 4-1: Gesamtsystem und Teilsysteme

    Hotel Reservation

    Persistent Store (DB)

    Web Presentation

    Reservation Business

    Logic

    34

  • Komponenten in UML 2.0

    15

    4.3 Darstellung der Komponente mit Schnittstellen Um den Rahmen dieser Arbeit nicht sprengen zu wollen, wird von nun an nur noch die Komponente „Persistent Store“ betrachtet.

    Abbildung 4-2: Komponente „Persistent Store“ mit Schnittstellen Abbildung 4-2 zeigt die betrachtete Komponente „Persistent Store“ und deren angebotenen Schnittstellen: DBTest prüft, ob eine Datenbankverbindung noch gültig ist, DBAccess ist für das Öffnen und Schließen der Datenbankverbindung zuständig, DBQuery ist für das Laden und Speichern von Objekten zuständig. Damit die Komponente ihre Dienste korrekt anbieten kann, benötigt diese ihrerseits eine Komponente, welche die Schnittstelle Rdbms anbietet. Abbildung 4-3 zeigt eine alternative Darstellung der Komponente als Blackbox:

    4.4 Komponentendiagramme Will man die Komponente und ihre Schnittstellen ausführlicher für andere Entwickler darstellen, so müssen Details zur Schnittstelle mit angegeben werden. Abbildung 4-4 zeigt die Komponente mit den Details der angebotenen und verwendeten Schnittstellen:

    Persistent Store

    DBAccess DBQuery

    DBTest Rdbms

    Abbildung 4-3: Komponente „Persistent Store“ in Blackbox-Darstellung

    Persistent Store

    DBAccess DBQuery DBTest Rdbms

    35

  • Komponenten in UML 2.0

    16

    Abbildung 4-4: Komponente und explizite Darstellung der Schnittstelle

    DBQuery

    retrieve(type : Object, search : String): Object store(obj : Object) : Boolean sqlFetch(str : String) : String

    Persistent Store

    DBAccess

    openDB(url : String, user : String, password : String) : Boolean closeDB() : Boolean

    DBTest

    checkConnection() : Boolean

    Rdbms

    open() close() select() insert() delete() fetch()

    36

  • Komponenten in UML 2.0

    17

    Soll das Innenleben der Komponente dargestellt werden, so ist folgendes Komponentendiagramm aus Abbildung 4-5 angebracht:

    Abbildung 4-5: Interne Darstellung der Komponente

    In Abbildung 4-5 erkennt man u.a. folgendes:

    • Die Komponente kommuniziert mit der Umgebung über insgesamt vier Ports. • Die angebotenen Schnittstellen sind DBTest, DBAccess und DBQuery, die

    verwendete externe Schnittstelle ist Rdbms. • Die Hauptaufgaben der Komponente werden durch die Klasse DBManager realisiert. • Ein Aufruf der Schnittstelle DBAccess mit den beiden Operationen openDB() oder

    closeDB() wird an die Instanz der Klasse DBManager delegiert.

    Rdbms

    0..1 0..*

    0..1

    retrieves stores

    0..*

    1

    handles

    DBQuery

    DBAccess

    created by

    1

    1 connect

    connectionCheck

    Persistent Store

    DBTest

    Connection

    checkConnection

    DBManager

    Query

    Object

    0..1

    37

  • Komponenten in UML 2.0

    18

    • Die Komponente verwendet intern eine weitere Komponente Connection. Diese bietet die beiden Schnittstellen connectionCheck und connect an.

    • Die externe Komponente Rdbms wird von der Komponente Connection und von den beiden Klassen DBManager und Query benötigt.

    4.5 Exemplarische Codierung in Java Die nachfolgenden Code-Fragmente sind gemäß neuestem EJB Standard 3.0 implementiert. Die Schnittstelle der Komponente PersistentStore sieht dabei wie folgt aus: PersistentStore.java: package pstore; import javax.ejb.Remote; interface DBQuery {. . .} interface DBAccess {. . .} interface DBTest {. . .} @Remote public interface PersistentStore extends DBQuery, DBAccess, DBTest { // Schnittstelle DBQuery public DBObject retrieve(DBObject object, String search); public boolean store(Object object); public String sqlFetch(String str); // Schnittstelle DBAccess public boolean openDB(String url, String user, String pw); public boolean closeDB(); // Schnittstelle DBTest public boolean checkConnection(); }; Die Komponente wird als zustandbehaftete Bean realisiert, da das intern verwendete Datenobjekt vom Typ DBManager für den gesamten Zeitraum der Benutzung der Komponente benötigt wird. PersistentStoreImpl.java: package pstore; import rdbms.*; import javax.ejb.Stateful; @Stateful public class PersistentStoreImpl implements PersistentStore { private DBManager manager; // Implementierung der Schnittstellen // . . . };

    38

  • Komponenten in UML 2.0

    19

    5 Zusammenfassung Mit Hilfe der komponentenbasierten Programmierung ist es möglich, komplexe Softwaresysteme in modulare, weitestgehend unabhängige Einheiten zu zerlegen, um diese später in unterschiedlichen Systemen flexibel einsetzen zu können. Diese Einheiten werden Komponenten genannt. Das Konzept der komponentenbasierten Softwareentwicklung fördert die Wiederverwendung von Software und macht die einzelnen Komponenten flexibel einsetzbar. Durch diese lose Kopplung der Komponenten wird eine Reduzierung der Komplexität erreicht. Grundvoraussetzung für ein korrektes Zusammenspiel zwischen Komponente und umgebendem Softwaresystem bzw. zwischen Komponenten untereinander ist die Schnittstellenkompatibilität. Jede Komponente besitzt eine oder mehrere Schnittstellen für die Kommunikation mit der Außenwelt. Über diese Schnittstellen können entweder Dienste angeboten oder aber externe Dienste z.B. von anderen Komponenten genutzt werden. Durch den Vorstoß der komponentenbasierten Programmierung wurde gleichzeitig die Notwendigkeit nach einer geeigneten Notation für den Entwurf und die Dokumentation derartiger Systeme laut. Mit der Einführung der UML 2.0 im Jahre 2004 wurde dieser Notwendigkeit Rechnung getragen, indem komponentenspezifische Modellierungselemente in die Sprache aufgenommen wurden. Wie in Kapitel 3 erläutert beinhaltet die UML 2.0 eine Vielzahl von Notationselementen zur Darstellung von Komponenten und deren Beziehungen untereinander. Während die Elemente „Component“, „Port“ und „Interface“ die Komponente an sich beschreiben, stellen die Elemente „Part“ und „Connector“ den internen Aufbau sowie das Zusammenspiel mit Subkomponenten dar. Das „Component diagram“ zeigt schließlich den kompletten Aufbau einer Komponente inklusive ihrer Subkomponenten. Ferner gehen aus einem Komponentendiagramm die Schnittstellen hervor, die über entsprechende Ports verfügbar sind, um die Komponente in ein bereits existierendes Softwaresystem „einstecken“ zu können. Das Komponentendiagramm bietet somit eine ideale Übersicht über den internen Aufbau und die Funktion einer Komponente. Zusammenfassend lässt sich feststellen, dass mit der Aufnahme komponentenspezifischer Notationselemente in die UML 2.0 ein entscheidender Beitrag zur Förderung und Unterstützung der komponentenbasierten Softwareentwicklung geleistet wurde. Somit ist es möglich, mittels standardisierter Notationen, komponentenbasierte Systeme zu modellieren und zu dokumentieren. Diese Möglichkeit stellt eine wichtige Voraussetzung für den Entwurf robuster Softwaresysteme dar.

    39

  • Komponenten in UML 2.0

    20

    6 Literaturverzeichnis Abschnitt 2.1 ist weitgehend von [PoeBac06] und [FieSta06] entnommen. Abschnitt 2.2 ist weitgehend von [Jeckle04] entnommen. Abschnitt 2.3 ist weitgehend von [JRHZQ04] und [BoJaRu04] entnommen. Das Beispiel und die Diagramme aus Kapitel 4 sind aus [ChoSch04] entnommen. BoJaRu04 James Rumbaugh, Ivar Jacobson, Grady Booch: The Unified Modeling

    Language Reference Manual - Second Edition, Addison-Wesley, New York, 2004

    ChoSch04 Micheal Jesse Chonoles, James A. Schardt: UML 2 für Dummies - Software-Design mit System, mitp-Verlag Bonn, 2004

    FieSta06 Christian Fiedler, Dominik Stadler: Komponenten und die objektorientierte Programmierung, Seminararbeit im WS 2005/2006 an der Fernuniversität Hagen

    Jeckle04 Vorlesung zur UML, http://www.jeckle.de/vorlesung/uml JRHZQ04 Mario Jeckle, Chris Rupp, Jürgen Hahn, Barbara Zengler, Stefan Queins: UML

    2 glasklar, Hanser Verlag, München 2004 Oester04 Bernd Oestereich: Objektorientierte Softwareentwicklung - Analyse und Design

    mit der UML 2.0, 6. Auflage, Oldenbourg Verlag München, 2004 OMG05 OMG: Unified Modeling Language - Superstructure, Version 2.0,

    http://www.omg.org PoeBac06 Renate Pöschl, Markus Bach: Komponentenbasierte Programmierung –

    Theoretische Grundlagen von Komponenten, Seminararbeit im WS 2005/2006 an der Fernuniversität Hagen

    SixWin06 Hans-Werner Six, Mario Winter: Software Engineering I -G