Proseminar: Entwurfsmuster und Frameworks Thema 11

„Entwurfsmuster und Frameworks“

Autoren:

René Eßer

Thorsten Pelz

Richard Schuller

Westfälische Str. 55

Düringer Str. 75

Tannenweg 1

5 74 62 Olpe

5 74 62 Olpe

3 56 06 Solms-Niederbiehl

esser@ti.et-inf.uni-siegen.de

pelz@ti.et-inf.uni-siegen.de

schuller@ti.et-inf.uni-siegen.de

Unter Betreuung von:

Prof. Hans Wojtkowiak & Dr. Klaus Quibeldey Cirkel

Inhaltsverzeichnis:

1. Einleitung

1.1 Historie: Die Anfänge

1.2 Entwurfsmuster: eine Begriffsbestimmung

2. Entwurfsmuster

2.1 Was versteht man unter Entwurfmustern?

2.2 Wie ist ein Entwurfsmuster aufgebaut?

2.3 Was ist ein Entwurfsmuster, was ist es nicht?

2.4 Beschreibung der Entwurfsmuster

2.4.1 Graphische Notation eines Entwurfsmusters

2.4.2 Textuelle Notation eines Entwurfsmusters

2.5 Klassifizierung der Entwurfsmuster

3. Frameworks

3.1 Was ist ein Framework?

3.2 Vergleich Klassenbibliotheken VERSUS Frameworks:

3.3 Was ist so gut an Frameworks?

3.4 Welche Nachteile haben Frameworks?

3.5 Vergleich Entwurfsmuster versus Frameworks:

4. Arbeiten mit Entwurfsmustern

4.1 Wie löst man Designprobleme mit Hilfe der Entwurfsmuster?

4.2 Finden der geeigneten Objekte

4.3 Bestimmung der Objektgranularität

4.4 Spezifizieren von Objektschnittstellen

4.5 Spezifikation der Objektimplementierungen

4.6 Klassen- versus Schnittstellenvererbung

4.7 Programmienen zur Schnittstelle, nicht zur Implementierung

4.8 Die Wiederverwendungsmechanismen arbeiten lassen

4.9 Vererbung versus Komposition

4.10 Delegation

4.11 Vererbung versus parametrisierte Typen

4.12 Beziehungen unter Laufzeit- und Kompilierzeitstrukturen

4.13 Entwerfen für Änderungen

4.14 Anwendungen

4.15 Wie findet man das richtige Entwurfsmuster?

4.16 Wie benutzt man Entwurfsmuster?

5. Das Model - View - Controller Entwurfsmuster (MVC)

6. Zusammenfassung

Literaturverzeichnis

1. Einleitung



Dieses Referat entstand im Informatik-Proseminar "Objektorientierte Konzepte und Anwendungen“ im WS 1996/97. Das Proseminar hatte die Zielsetzung, in die OOx Thematik einzuführen, Präsentationstechniken einzustudieren, sowie Orientierung im Studium in Bezug auf das Anforderungsprofil „Dipl.Ing.“ und „Informatik-Systemtechnik“ zu bieten.


Unter dem Untertitel „OO und Informatik“ behandelt das folgende Referat das Thema „Entwurfsmuster und Frameworks“ und stützte sich dabei im Wesentlichen auf das Buch „Design Patterns" von Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides, da sich dieses Buch 1995 als ein Bestseller herausgestellt hat und bereits jetzt als Standardliteratur auf diesem Forschungsgebiet gelten darf..[Gam95]


Dieses Referat hat zum Ziel, einen Überblick über Entwurfsmuster und Frameworks zu geben, deren Beschreibung und Klassifizierung zu erläutern, sowie deren Gebrauch aufzuzeigen.


1.1 Historie: Die Anfänge

Abb. 1.1 Sierpinskifraktal


Seit Anfang der 90er Jahre versucht die Informatik (genauer: die Objektorientierung), die Wiederverwendung von Problem-Lösungspaaren durch „Entwurfsmuster" zu abstrahieren. Dabei sind die Bücher des Architekten Christopher Alexander oft zitierte Quellen; er veröffentlichte bereits 1977 insgesamt 253 Entwurfsmuster des Gebäudeentwurfs [Alexander 1977]. In der Informatik dokumentieren Entwurfsmuster das langjährige Erfahrungswissen von Softwarearchitekten. Das oben dargestellte Sierpinskifraktal (Abb.1) verdeutlicht eine wesentliche Eigenschaft eines Entwurfsmusters: Ein Muster bekommt erst eine wohlgeformte und ausgereifte Struktur, wenn es sich in der Praxis mehrmals etabliert hat. Es wird nicht neu erfunden, sondern kristallisiert sich aus dem Erfahrungswissen unzähliger Entwürfe heraus. Anfängern soll es so ermöglicht werden, in nur kurzer Zeit über das Wissen von Experten zu verfügen. Ziel der Entwurfsmuster ist es, ein Softwaresystem so zu entwerfen, daß es wiederverwendbarer wird.


Wird ein Softwaresystem unter Zuhilfenahme von Entwurfsmustern (engl. Design Patterns) entwickelt und dokumentiert, so trägt das maßgeblich zur Qualität, Klarheit und Wartbarkeit bei.


Die Entwicklung von integrierten Programmsystemen soll einerseits kostengünstig durchgeführt werden, andererseits muß die entwickelte Software auch Qualitätsanforderungen, wie beispielsweise Korrektheit, Robustheit usw. genügen. [Mey90] Diese sich eigentlich widersprechenden Anforderungen können insbesondere durch den Einsatz


zumindest teilweise erfüllt werden.


Der Preis, aber auch die Qualität objektorientierter Software wird dabei in der Entwurfsphase maßgeblich durch die Wiederverwendung von Komponenten beeinflußt. Zwei unterschiedliche Arten der Wiederverwendung sind möglich:



In beiden Fällen wird eine nachhaltige Kostenreduktion erreicht, da bereits erstellte Klassen und Entwürfe nicht neu entwickelt werden müssen. Außerdem erhöht sich die Softwarequalität, da bereits erprobte Klassen bzw. Entwürfe genutzt werden können.

Insbesondere der Einsatz von Entwurfsmustern hat eine zweifache Bedeutung in Hinsicht auf die Wiederverwendbarkeit.


Denn durch Entwurfsmuster können einerseits Entwürfe wiederverwendet werden, andererseits können - bei entsprechender Auslegung - Entwurfsmuster zur Entwicklung wiederverwendbarer Komponenten beitragen.






1.2 Entwurfsmuster: eine Begriffsbestimmung


Die Entwurfsmuster sind keine Erfindung der Informatiker.


Der Begriff "Muster" existiert schon sehr lange. Praktisch in jeder Wissenschaft hat Muster seine Bedeutung, allerdings ist sie in zweierlei Hinsicht unterschiedlich:


  1. Die Rolle, die Muster in einer Wissenschaft spielen, ist oft von extrem unterschiedlicher Bedeutung.

  2. Das, was man unter „Muster" versteht, kann je nach Wissenschaft sehr stark variieren.


Im DUDEN [Duden89] wird ein „Muster" definiert als:


  1. Vorlage, Modell, nach dem etwas gefertigt, hergestellt wird.

  2. sich auf einer Fläche, auf Stoff, Papier o.ä. wiederholende Verzierung.

  3. Probe, kleine Menge zur Ansicht, an der man die Beschaffenheit des Ganzen erkennen kann.


Darüber hinaus existieren in einigen Wissenschaften ganz spezielle Begriffsbestimmungen des Wortes Muster, deren richtige Bedeutung man nur mit sehr viel Phantasie den allgemeinen Begriffsdefnitionen, wie sie in Bedeutungswörterbüchern angegeben sind, entnehmen kann. So gibt es viele Anwendungsbereiche, die Muster auf eine ganz unterschiedliche Art gebrauchen:



Und die Liste könnte beliebig erweitert werden. Muster als kognitive Skripte sind ein zentrales Thema der Kreativitäts- und Gedächtnisforschung.


Darüber hinaus haben „Musterbücher" eine lange Tradition. Nicht der in der Softwaretechnik oft zitierte Architekt Christopher Alexander, sondern Handwerker des Mittelalters waren die ersten Autoren von Musterbüchern. Das berühmteste ist das Bauhüttenbuch des Villard De Honnecourt, das um 1240 in Paris erschien [Brockhaus, 1991].


Alexander beschreibt die Entwurfsmuster folgendermaßen:


„Each Pattern describes a problem which occurs over and over again in our enviroment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same.“[AIS77]


was übersetzt soviel bedeutet wie:


„Jedes Muster beschreibt ein in unserer Umwelt beständig wiederkehrendes Problem und erläutert den Kern der Lösung für dieses Problem, so daß Sie diese Lösung beliebig oft anwenden können, ohne sie jemals ein zweites mal gleich auszuführen.“[Gam96,S.2f]


Die Informatik hat die Entwurfsmuster erst vor kurzer Zeit für sich entdeckt. Die Entwurfsmuster sind in der Informatik Gegenstand der Forschung. Seit der Softwarekrise in den 60er Jahren, die durch explosionsartig wachsende Komplexität der Software entstanden ist, sucht man in der Informatik nach Methoden, die die ständig wachsende Komplexität der Software in den Griff bekommen sollen. Das Problem bei der Softwareentwicklung ist das Fehlen von regulären Strukturen, wie z.B. Zellbibliotheken im Hardwareentwurf, die einen Aufbau nach dem "Baukastenprinzip" erlauben würden.


Entwurfsmuster - oder Design Patterns - beschreiben abstrakte Lösungen für immer wiederkehrende Analyse- und Design-Probleme. Wird ein Softwaresystem unter Zuhilfenahme von Entwurfsmustern entwickelt und dokumentiert, so trägt das maßgeblich zur Qualität, Klarheit und Wartbarkeit bei.


Man hat beachtliche Fortschritte bei dem Modellieren von Softwaresystemen erreicht. Von mächtigen Hochsprachen und Datenbankmanagementsystemen bis hin zu Analyse- und Designmethoden gibt es heute viele Werkzeuge, die den Softwareentwurf auf einem hohen Abstraktionsniveau erlauben. Das Fehlen der regulären Strukturen führt allerdings dazu, daß man das "Rad" immer wieder neu erfinden muß.

Man versucht die einmal entwickelte Software wiederzuverwenden z.B. in Form von Funktions-, Modul-, und Klassenbibliotheken. Dies führt zur kapitalintensiven Softwareentwicklung, weil die eingesetzten Softwarekomponenten in der Regel eingekauft werden müssen. Ein anderes Problem ist es, die richtigen Komponenten zu finden, denn die Wiederverwendung lohnt sich nur, wenn das Beschaffen der Komponenten billiger als die Eigenentwicklung ist.

Die erworbenen Komponenten müssen in der Regel noch angepaßt werden, was auch immer geringen Aufwand bedeutet. Der objekt-orientierte Ansatz bietet hier erhebliche Abhilfe, denn man kann die Klassenbibliotheken durch Vererbung und Parametrisierung anpassen, ohne den Quellcode zu ändern. Diese Arten der Verwendung beziehen sich auf die Software selbst, die Entwurfsmuster führen zum dem Ziel, die erfolgreichen Vorgehensweisen bei der Softwareentwicklung wiederzuverwenden.


Dazu heißt es in der Einleitung zu „Design Patterns“ von Gamma et al. :


„Der Entwurf objektorientierter Software ist schwer. Noch schwerer aber ist der Entwurf wiederverwendbarer objektorientierter Software. Man muß die relevanten Objekte aufspüren, sie zu Klassen passender Granularität abstrahieren, ihre Schnittstellen sowie Vererbungshierarchien definieren und die zentralen Beziehungen zwischen ihnen festlegen. Ein Entwurf muß sowohl den vorliegenden spezifischen Anforderungen genügen als auch allgemein genug sein, um zukünftigen Problemen und Anforderungen begegnen zu können. Des weiteren will man die Revision von Entwürfen vermeiden oder sie zumindest minimieren. Erfahrene objektorientierte Entwickler wissen, daß es schwer, wenn nicht gar unmöglich ist, einen wiederverwendbaren und flexiblen Entwurf gleich beim ersten MaI "richtig ' zu machen. Vor der Fertigstellung eines Entwurfs versuchen sie üblicherweise ihn mehrmals wiederzuverwenden, wobei sie ihn dann jedesmal verändern.


Gleichwohl erstellen erfahrene objektorientierte Entwickler gute Entwürfe. Unerfahrene Entwickler hingegen kapitulieren oft vor der großen Anzahl an Entwurfsmöglichkeiten und greifen auf nicht objektorientierte, zuvor aber einmal von ihnen verwendete Techniken zurück. Es dauert lange, bis Anfänger verstehen, worum es bei gutem objekt-orientiertem Entwurf eigentlich geht. Offenkundig wissen erfahrene Entwickler etwas, was unerfahrene nicht wissen. Was ist das?


Experten wissen es zu vermeiden, jedes Problem von Grund auf neu anzugehen. Statt dessen verwenden sie Lösungen wieder, die sie zuvor erfolgreich eingesetzt haben. Haben sie einmal eine gute Lösung gefunden, verwenden sie diese wieder und wieder. Solche Erfahrung ist Teil dessen, was sie zu Experten macht. Als Folge davon lassen sich in vielen objektorientierten Systemen wiederkehrende Muster von Klassen und kommunizierenden Objekten finden. Diese Muster lösen spezifische Entwurfsprobleme und machen objektorientierte Entwürfe flexibler, eleganter und im Endeffekt erst wiederverwendbar. Entwickler, die auf diese Muster zurückgreifen, verwenden erfolgreiche Entwürfe wieder. Kennt ein Entwickler diese Muster, so kann er sie unmittelbar auf vorliegende Entwurfsprobleme anwenden, ohne die Lösung neu entdecken zu müssen.


Eine Analogie soll dies verdeutlichen: Romanschriftsteller und Bühnenautoren entwickeln ihre Handlungen praktisch nie von Grund auf neu. Vielmehr verwenden sie Muster wie "tragisch gefallener Held", wie zum Beispiel Macbeth oder Hamlet, oder "der Liebesroman“, erhältlich in beliebiger Anzahl. Auf dieselbe Weise verwenden objektorientierte Entwickler Muster wie "Repräsentiere Zustand durch Objekte“ oder "Dekoriere Objekte“, so daß man einfach Eigenschaften hinzufügen und entfernen kann. lst das Muster erst einmal bekannt, so ergeben sich viele Entwurfsentscheidungen automatisch.


Wir alle kennen die Bedeutung von Entwurfserfahrung. Wie oft hatten Sie bei einem Entwurf bereits ein Déjà-vu-Erlebnis, jenes Gefühl, ein Problem bereits einmal gelöst zu haben, aber nicht mehr genau zu wissen wo und wie? Wenn Sie sich an die Details des früheren Problems und daran, wie Sie es gelöst haben, erinnern könnten, dann könnten Sie diese Erfahrung wiederverwenden anstatt sie erneut machen zu müssen. Leider aber sind wir nicht sonderlich gut darin, Erfahrungen beim Softwareentwurf festzuhalten, so daß sie von anderen verwendet werden können.“


Dies führt uns dazu, diese von uns einmal gemachten Erfahrungen in einer bestimmten Form, den Entwurfsmustern, festzuhalten und „mitteilbar“ zu machen, damit andere von den von uns gemachten Erfahrungen profitieren können.


Daraus kann man schließen, daß der Einsatz der Entwurfsmuster die Wiederverwendung des Wissens bedeutet und damit die Produktivität steigert, da das Wissen bereits existiert und nicht neu erfunden werden muß. Andererseits sind Entwurfsmuster der schnelle Weg, einem Neuling das Wissen eines Experten zu verschaffen. So lehrt Christopher Alexander Architektur anhand von ca. 250 Mustern.





2. Entwurfsmuster


2.1 Was versteht man unter Entwurfmustern?


Nach der allgemeinen Definition von Entwurfsmustern in Abschnitt 1.2 möchten wir nun eine genauere Bestimmung für den Bereich des Softwareentwurfes vornehmen.


In ihrem Buch „Design Patterns"[Gam95] sagen Gamma et al., daß auf die im Buch beschriebene objekt-orientierte Entwurfsmuster die oben zitierte Beschreibung von Christopher Alexander in der Hinsicht zutrifft, daß ein Muster immer aus einem Problem und in Kontext dazu stehender Lösung besteht, man bezeichnet es auch als "Problemlösungspaar“.


2.2 Wie ist ein Entwurfsmuster aufgebaut?

Die Entwurfsmuster bestehen grob aus vier Elementen, die ihrerseits wieder unterteilt werden:



Insgesamt kommt man, wenn man ein Entwurfsmuster nach Gamma et al. spezifizieren will auf 13 Elemente:


Entwurfsmustername bestehend aus:


Der Entwurfsmustemame ist ein Stichwort, welcher das Entwurfsproblem, dessen Lösung und die daraus folgenden Konsequenzen in ein bis zwei Worten beschreibt. Die Benennung eines Muster erhöht unser Entwurfsvokabular, so das wir den Entwurf auf einer höheren Abstraktionsebene vornehmen können. Das Vorhandensein eines solchen Entwurfsvokabulars für Muster erleichtert es uns mit unseren Kollegen, und in unserer Dokumentation, über dieses Thema zu sprechen. Es ist keine einfache Angelegenheit, einen aussagekräftigen Entwurfsmusternamen zu finden.


Problem bestehend aus:




Das Problem beschreibt, in welchen Fällen das Entwurfsmuster anzuwenden ist. Es erläutert das Problem und seinen Kontext. Es beschreibt spezifische Designprobleme, wie Repräsentation von Algorithmen als Objekte. Es kann auch Klassen- oder Objektstrukturen beschreiben, die typisch für ein inflexibles Design sind. Manchmal beinhaltet das Problem eine Liste von Bedingungen, die erfüllt werden müssen, bevor es Sinn macht, das Muster einzusetzen.


    Lösung bestehend aus:



Die Lösung beschreibt Entwurfselemente, deren Beziehungen, Pflichten und Zusammenarbeit. Sie beschreibt kein spezielles, konkretes Design oder Implementierung, denn Muster sind wie Schablonen und können in vielen unterschiedlichen Situationen angewendet werden. Statt dessen stellen die Entwurfsmuster eine abstrakte Beschreibung des Designproblems dar und beschreiben, wie eine allgemeine Anordnung von Elementen ( z. B. Klassen und Objekte ) dieses Problem lösen kann.


    Konsequenzen bestehend aus:


Die Konsequenzen sind Ergebnisse und Folgen der Anwendung des Entwurfsmusters. Obwohl die Konsequenzen bei der Beschreibung der Designentscheidungen oft unausgesprochen bleiben, sind sie kritisch für die Auswertung der Designaltemativen und für das Verständnis der Kosten und Nutzen der Anwendung des Entwurfsmusters.


Die Konsequenzen für die Software beinhalten oft Speicher- und Laufzeitanforderungen. Sie können sehr wohl Sprach- und Implementierungsentscheidungen betreffen. Seit die Wiederverwendung oft ein bedeutender Faktor im objektorientierten Design darstellt, beinhalten die Konsequenzen des Entwurfsmusters seine Einwirkungen auf Flexibilität, Erweiterbarkeit oder Portierbarkeit des Systems. Explizite Auflistung der Konsequenzen hilft sie zu verstehen und zu bewerten.


Die Suche nach einem geeigneten Muster ist natürlich nicht einfach, und vor allem subjektiv. Unterschiedliche Faktoren, wie z. B. Bildungsgrad oder Vertrautheit mit dem Problemgebiet, beeinflussen die Interpretation des Musterbegriffs. Ein Muster, das für eine Person wichtig erscheinen mag, kann für eine andere Person keine große Rolle im Entwurfsprozeß spielen und wird lediglich als ein primitiver Baustein eingesetzt.




2.3 Was ist ein Entwurfsmuster, was ist es nicht?


Gamma et al. [Gam95,S.3] gehen einen Schritt weiter und erörtern was ein Entwurfsmuster nicht ist:


„Design patterns are not about designs such as linked lists and hash tables that can be encoded in classes and reused as is. Nor are they complex, domain-specific designs for an entire application or subsystem. The design patterns in this book are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context. "


Das Entwurfsmuster benennt, abstrahiert und identifiziert Schlüsselaspekte der zentralen Designstruktur, die es erlauben, diese Struktur zum Erzeugen eines wiederverwendbaren objekt-orientierten Designs hilfreich zu machen. Das Entwurfsmuster legt beteiligte Klassen und Instanzen, deren Rollen und Beziehungen sowie Verteilung der Zuständigkeiten fest. Jedes Entwurfsmuster konzentriert sich an einem speziellen objekt-orientierten Designproblem oder Aufgabe. Es beschreibt, wann es angewendet werden kann, ob es im Hinblick auf andere Designeinschränkungen angewendet werden kann und welche Konsequenzen und Auswirkungen seine Benutzung mit sich bringt. Bei den Beispielen wird hauptsächlich C++ Code und manchmal Smalltalk-Code verwendet, um die Implementierungen zu veranschaulichen.


Obwohl Entwurfsmuster objekt-orientierte Designs beschreiben, basieren sie auf praktischen Lösungen, die hauptsächlich in objekt-orientierten Programmier-sprachen wie C++ oder Smalltalk und nicht in prozeduralen Programmiersprachen (PASCAL,ADA, C) oder dynamischen objekt-orientierten Programmiersprachen (Clos,Self) implementiert worden sind.


C++ und Smalltalk wurden aus pragmatischen Gründen gewählt. Viele Programmierer sind mit diesen Programmiersprachen vertraut und die Popularität dieser Programmiersprachen wächst immer weiter. Die Wahl der Programmiersprache ist wichtig, weil durch die Programmiersprache, die Sicht auf das Problem beeinflußt wird. Die Entwurfsmuster setzen Sprachelemente auf Smalltalk- bzw. C++ Niveau voraus. Das ist das Entscheidungskriterium für die einfache Implementierbarkeit der Muster in der gewählten Programmiersprache.


Auf der anderen Seite werden einige der Entwurfsmuster, die Erich Gamma et al. in ihrem Buch beschreiben, von einigen weniger bekannten objekt-orientierten Programmiersprachen direkt unterstützt. Außerdem existieren genug Unterschiede zwischen C++ und Smalltalk, so daß einige der Muster in einer Sprache einfacher auszudrücken sind als in der anderen.




2.4 Beschreibung der Entwurfsmuster


Nachdem der erste Überblick von den Entwurfsmustern nun gegeben ist, stellt sich die Frage, wie man die Entwurfsmuster beschreiben kann. Entwurfsmuster müssen auf eine Art und Weise beschrieben werden, die einerseits von jedem verstanden werden kann und andererseits von der Beschreibung her hinreichend sein muß, um demjenigen, der ein Entwurfsmuster studiert, einen allgemeinen Überblick verschaffen zu können.


Man kennt zwei wichtige Klassen von Beschreibungsmöglichkeiten. Das sind graphische und textuelle Notationen.




2.4.1 Graphische Notation eines Entwurfsmusters


Gamma et al. [Gam96] verwenden die OMT-Notation (Object Modelling Technique). Graphische Notationen sind wichtig und gebräuchlich, aber sie allein genügen nicht, weil sie lediglich das endgültige Produkt des Entwurfsprozesses in Form von Klassen- und Objektdiagrammen (siehe Abb.2.1) und deren Beziehungen untereinander sind. Will man allerdings den Entwurf wiederverwenden, dann müssen auch alle Zusammenhänge, Entscheidungen und Alternativen, die zum Entwurf in seiner Endform geführt haben, ebenfalls berücksichtigt werden. Ebenso wichtig sind konkrete Beispiele, weil durch sie das Entwurfsprodukt im Einsatz beobachtet werden kann.


Abb. 2.1 Übersicht über die verschiedenen graphischen Notationen [Gam96,S.432]



2.4.2 Textuelle Notation eines Entwurfsmusters


Zur Beschreibung der Entwurfsmuster verwenden Gamma et al. [Gam96] eine textuelle Beschreibung in einem konsistenten Format, das folgendermaßen aussieht:



Der Mustername vermittelt kurz die Essenz des Musters. Ein guter Name ist wichtig, denn er wird zu einem Teil des Designvokabulars. Die Klassifizierung eines Musters basiert auf den im Abschnitt 2.5 dargestellten Schema.




Eine kurze Sammlung der Antworten auf folgende Fragen:




Andere bekannte Namen für dieses Muster, falls welche bekannt sind.



Eine Szenariobeschreibung, die das Designproblem beschreibt und zeigt, wie die Klassen- und Objektstrukturen in dem Muster dieses Problem lösen.



In welchen Situationen können die Entwurfsmuster angewendet werden? Welche Designbeispiele gibt es, die direkt vom Muster angesprochen werden? Wie erkennt man diese Situationen wieder?




Graphische Repräsentation der in dem Entwurfsmuster benutzten Klassen. Dabei wird OMT-Notation verwendet. Es werden auch Interaktionsdiagramme verwendet, um die Sequenzen von Kommunikationsvorgängen zwischen den Objekten zu beschreiben.



Die im Entwurfsmuster vertretenen Klassen und/oder Objekte sowie deren Aufgaben.



Wie arbeiten die Teilnehmer zusammen, um ihre Aufgaben auszuführen.



Wie unterstützt das Muster seine Ziele? Welche Auswirkungen und Ergebnisse bringt die Benutzung des Musters mit sich? Welcher Aspekt der Systemstruktur erlaubt es, das System unabhängig zu variieren?



Welche Fallen, Tips oder Techniken sollten man bei der Implementierung des Musters beachten? Gibt es sprachspezifische Auflagen?



Codefragmente die verdeutlichen, wie das Muster in C++ oder Smalltalk implementiert werden kann.



Beispiele der Anwendung des Musters in vorhandenen Systemen.




Welche Entwurfsmuster stehen in einer engen Beziehung zu diesem Muster? Welche wichtige Unterschiede gibt es? Mit welchen anderen Mustern sollte dieses Muster benutzt werden?



2.5 Klassifizierung der Entwurfsmuster


Eine mögliche Klassifizierung der Entwurfsmuster ist die Einteilung wie sie im Buch von Gamma et al. „Entwurfsmuster“ [Gam96,S.12] vorgestellt wird (s. Tabelle 1). Wobei die Muster nach Gültigkeitsbereich und Aufgabe unterteilt werden.


Tabelle 1


Im Gültigkeitsbereich unterscheidet man zwischen Klassen- und Objektbasierend.






In Aufgabe unterteilt man erneut in Erzeugungs-, Struktur- und Verhaltens Mustern.






Abb.2.2[Gam96,S.13]



3. Frameworks


3.1 Was ist ein Framework?


Ein Framework besteht aus einer Sammlung von Klassen, die untereinander kooperieren. Sie bilden einen wiederverwendbaren Entwurf für eine spezielle Softwareklasse.


In dem Framework wird der Aufbau der Anwendung festgelegt. Es wird eine Überstruktur definiert, so daß der Entwickler sich nur noch um Besonderheiten seiner Anwendung kümmern muß. Bei den Frameworks wird die Wiederverwendbarkeit des Designs besonders betont.


Während man bei den Funktionsbibliotheken das Hauptprogramm schreibt und dann durch Aufrufe den Code wiederverwendet, steht bei den Frameworks das Hauptprogramm zu Verfügung und es muß der Code geschrieben werden, der vom Hauptprogramm aufgerufen wird.


Damit sind die Designentscheidungen des Entwicklers, der das Framework anwendet, eingeschränkt. Es bringt eine Reihe von Vorteilen mit sich:



Die Frameworks sind am schwersten zu entwerfen, weil eine einzige Architektur in allen Anwendungen des Problemgebiets arbeiten soll. Jede wesentliche Änderung im Frameworkdesign würde seine Vorteile erheblich reduzieren, denn der Hauptbeitrag des Frameworks zu einer Anwendung ist die Systemarchitektur, die er definiert.

Deswegen ist das Hauptziel beim Entwurf von Frameworks, sie so flexibel und erweiterbar zu halten, wie es nur möglich ist. Ausgereifte Frameworks beinhalten normalerweise eine Menge von (Entwurfs-)Mustern. Die Muster helfen dabei die Frameworkarchitektur an mehrere unterschiedliche Anwendungen anpaßbar zu halten, ohne sie zu umständlich ändern zu müssen.

Ein weiterer Vorteil kommt hinzu, wenn das Framework mit den in ihm eingesetzten Entwurfsmustern dokumentiert ist. Falls die Entwickler mit den Mustern vertraut sind, bekommen sie schneller Durchblick in die Frameworkarchitektur, und wenn es nicht der Fall ist, können sie trotzdem davon profitieren, da sie die Entwurfsmusterstrukturen der Dokumentation entnehmen können.


3.2 Vergleich Klassenbibliotheken VERSUS Frameworks:


Frameworks sind eine „Art von Klassenbibliotheken“. Der Unterschied zu anderen Klassenbibliotheken besteht darin:



Dieser Vorteil wird bei der dynamischen Bindung in objekt-orientierten Sprachen erreicht, indem eine Operation in einer Klassenbibliothek definiert, aber in einer Unterklasse implementiert werden kann.



3.3 Was ist so gut an Frameworks?


Ein Framework ist nicht nur eine Sammlung von Klassen, sondern es definiert auch ein generisches Muster. Beim Benutzen des Frameworks wird ein vorhandenes Design wiederverwendet, daß spart Zeit, Mühen und Kosten. Wegen dem bidirektionalen Fluß von Daten kann ein Framework viel funktioneller eingesetzt werden, als eine traditionelle Klassenbibliothek. Außerdem spart es zusätzliche Zeit, Mühen und Kosten, weil man nicht mehr so viel Programmcode schreiben muß, sondern ein Großteil des Codes schon im Framework enthalten ist.


3.4 Welche Nachteile haben Frameworks?


Um ein Framework benutzen zu können, muß man es erst lernen und verstehen. Und das ist bei der Größe und Komplexität der Frameworks sehr schwer und dauert auch recht lange. Deshalb ist es auch noch Niemandem gelungen, Frameworks auf einfache und kurze Weise zu dokumentieren, obwohl dies sicher, ähnlich wie bei den Entwurfsmustern, auch eine lohnenswerte Aufgabe wäre.


3.5 Vergleich Entwurfsmuster versus Frameworks:


Frameworks sind Programmcode (Software), wohingegen Entwurfsmuster Wissen und Information über Software (ALSO KEIN CODE!) sind. Entwurfsmuster können dazu genutzt werden, um Frameworks zu beschreiben. Ein Teil oder Aspekt eines Frameworks kann eine Realisierung eines Entwurfmusters sein.

Da Muster und Frameworks einige Ähnlichkeiten haben, fragen sich die Leute oft, worin und ob sie sich überhaupt unterscheiden. Sie unterscheiden sich in drei wichtigen Aspekten:



Schlußsatz:

Frameworks werden immer wichtiger. Mit ihrer Hilfe erreichen objektorientierte Systeme den höchsten Grad an Wiederverwendung. Größere objektorientierte Anwendungen werden aus Schichten von Frameworks bestehen, die miteinander zusammenarbeiten. Der Großteil des Anwendungsentwurfs und Anwendungscodes wird aus den verwendeten Frameworks stammen oder von ihnen beeinflußt sein.



4. Arbeiten mit Entwurfsmustern


4.1 Wie löst man Designprobleme mit Hilfe der Entwurfsmuster?


Entwurfsmuster lösen auf unterschiedliche Art und Weise viele Probleme, mit denen der Entwickler beim objektorientierten Ansatz immer wieder konfrontiert wird.


4.2 Finden der geeigneten Objekte


Objekt-orientierte Programme bestehen aus Objekten. Ein Objekt beinhaltet sowohl Daten als auch Prozeduren die auf diesen Daten arbeiten. Diese Prozeduren werden Methoden oder Operationen genannt. Ein Objekt führt eine Operation aus, wenn es eine Nachricht (request / message) von einem Klienten (Client) empfängt.



Der schwierige Teil im objektorientierten Entwurf ist die Zerlegung eines Systems in Objekte. Diese Aufgabe ist so kompliziert, weil mehrere Faktoren eine Rolle spielen: Datenkapselung, Granularität, Zusammenhänge, Flexibilität, Leistung, Wiederverwendung usw. Alle diese Faktoren beeinflussen oft den Entwurf.


Objekt-orientierte Entwurfsmethoden unterscheiden sich in dem Sinne, daß das Zerlegen eines Systems in Objekte auf verschiedene Art und Weise geschehen kann. Man kann


das Problem aufschreiben und dann alle Substantive und Verben herauspicken. Damit sind die ersten miteinander kommunizierenden Klassen mit ihren Methoden vorhanden. Oder man kann sich auf die Zusammenhänge und Verantwortlichkeiten des Systems konzentrieren. Man kann auch das System in der realen Welt modellieren und die Objekte, die bei der Analysephase gefunden wurden, in die Entwurfsphase hineinbringen. Welche der drei Methoden die beste ist, ist und wird umstritten bleiben.


Viele Objekte, die bei der Entwurfsphase zu sehen sind, kommen aus der Analysephase. Es ist aber üblich, daß viele Entwürfe in der objektorientierten Welt, Klassen beinhalten, die keine Entsprechung in der realen Welt haben (z. B. Arrays). Bei diesem Problem bieten Entwurfsmuster einen Lösungsansatz, so findet sich im Buch von Gamma et al. ein Muster namens "Composite", das sich mit der Behandlung von Klassen (Objekten), die in der realen Welt überhaupt nicht existieren, befaßt. Diese Entwurfsmethodik fördert die Wiederverwendung.


„Strict modeling of the real world leads to a system that reflects today's realities but not necessarily tomorrow's. The abstractions that emerge during Design are key to making a design flexible.“[Gam95,S.11]




4.3 Bestimmung der Objektgranularität


Die Objekte in einem Entwurf können in Größe und Anzahl variieren. Sie können Teile der Hardware darstellen, oder auch komplette Systeme oder Anwendungen. Wie kann entschieden werden, was in einem Entwurf als Objekt dargestellt werden kann?


Entwurfsmuster behandeln unter anderem auch dieses Thema. Es gibt Entwurfsmuster, die beschreiben, wie komplette Subsysteme durch Objekte dargestellt werden können. Sie bieten Unterstützung bei Entwürfen, deren Anzahl von Klassen groß ist, und die Granularität der Objekte fein gehalten wird. Andere Entwurfsmuster beschreiben, wie man Objekte in kleinere Objekte zerlegen kann.



4.4 Spezifizieren von Objektschnittstellen


Jede Operation, die in einer Klasse deklariert wurde, wird durch den Operationsnamen, ihre Parameter und ihren Rückgabewert spezifiziert. Dies ist auch bekannt als die Signatur (Signature) der Operation. Die Gesamtheit der Signaturen der Operationen, die in einem Objekt definiert wurden, bildet die Schnittstelle (Interface) des Objekts. Die Schnittstelle eines Objekts beschreibt also die Reihe von Aufforderungen, die von anderen Objekten zu diesem Objekt gesendet werden können. Nur Aufforderungen, (die in Form einer Nachricht zu dem Objekt zugeschickt werden), die einer Signatur innerhalb der Objektschnittstelle entsprechen, können vom Objekt empfangen und bearbeitet werden.


Ein Typ (Type) ist ein Name um eine Schnittstelle zu bezeichnen. Man kann sagen, ein Objekt habe den Typ „Window`, wenn es, alle Anforderungen für die Operationen, die in der Schnittstelle namens „Window` definiert wurden, akzeptiert. Ein Objekt kann mehrere Typen haben, und grundsätzlich verschiedene Objekte können den gleichen Typ haben. Darüber hinaus, kann ein Teil der Objektschnittstelle einen gewissen Typ haben und ein anderes Teil einen anderen. Schnittstellen können andere Schnittstellen beinhalten. Man bezeichnet einen Typ als Subtyp eines anderen, wenn seine Schnittstelle die Schnittstelle seines Supertyps beinhaltet. Man kann auch sagen, daß der Subtyp die Schnittstelle seines Supertyps erbt.


Schnittstellen sind fundamental in objektorientierten Systemen. Objekte sind nur durch ihre Schnittstellen bekannt. Es gibt keine andere Möglichkeit, über ein Objekt irgend etwas zu erfahren oder es aufzufordern, etwas zu tun, ohne es über seine Schnittstelle anzusprechen. Die Objektschnittstelle verrät nichts über die "Interna" dieses Objekts. Verschiedene Objekte können die gleiche Aufforderung auch unterschiedlich implementieren. Dies bedeutet, daß unterschiedlich implementierte Objekte identische Schnittstellen haben können.


Wenn eine Aufforderung zu einem Objekt gesendet wird, hängt die Operation, die tatsächlich ausgeführt wird, sowohl von der Aufforderung, als auch von dem empfangendem Objekt ab. Verschiedene Objekte, die identische Aufforderungen in ihren Schnittstellen beinhalten, können diese Aufforderungen unterschiedlich implementieren. Diese Assoziation einer Aufforderung mit einem Objekt während der Laufzeit nennt man dynamisches Binden (dynamic binding).


Dynamisches Binden bedeutet, daß die Ausführung einer Operation als Ergebnis einer Aufforderung erst während der Laufzeit an eine bestimmte Implementierung gebunden wird. Darüber hinaus erlaubt das dynamische Binden Substitution der Objekte untereinander, die über identische Schnittstelle verfügen, zur Laufzeit. Dieses "Verhalten" nennt man Polymorphie (Polymorphism). Es ist ein fundamentales Merkmal der Objektorientierung. Mit Hilfe von Entwurfsmustern kann man Schnittstellen durch Identifizieren ihrer „Schlüsselelemente" und der Art von Daten, die zur Schnittstelle zugeschickt werden, definieren. Ein Entwurfsmuster kann auch zeigen, was zu der Schnittstelle nicht gehört.


4.5 Spezifikation der Objektimplementierungen


Eine Objektimplementierung wird bei der Klasse des Objekts definiert. Die Klasse spezifiziert interne Daten eines Objekts und deren Darstellung und definiert Operationen, die diese Daten ändern können. Die Beschreibungen der Objektimplementierungen basieren auf der OMT-Notation. Die Klasse wird als ein Rechteck mit dem Klassennamen im oberen Teil dargestellt. Unter dem Klassennamen stehen Operationen und denen folgen Daten.

Diese drei Bereiche werden durch Linien getrennt (Abb.4.1).


Abb. 4.1 OMT-Notation einer Klasse [Gam96,S.17]


Objekte werden erzeugt, indem sie von Klassen instantiiert werden. Es können also mehrere Objekte einer Klasse erzeugt werden.

Neue Klassen kann man durch Gebrauch von Klassenvererbung von existierenden Klassen ableiten. Wenn die Subklasse von ihrer Elternklasse(Superklasse) erbt, werden alle Daten- und Operationsdefnitionen der Elternklasse geerbt.

Die Vererbungsbeziehung wird durch eine senkrechte Linie und ein Dreieck dargestellt.


(Abb. 4.2) Elternklasse



(Abb. 4.3) Abstrakte Klasse



(Abb. 4.4) Erweiterte Klasse


Außerdem wird auch zwischen abstrakten und konkreten Klassen unterschieden. Der Unterschied besteht darin, daß abstrakte Klassen (siehe Abb. 4.3) nicht instantiiert werden können. In der OMT-Notation werden Namen von abstrakten Klassen kursiv geschrieben.

Eine Abbildung kann ferner Pseudocode enthalten, welcher in einem mit einem Eselsohr versehenen Rechteck erscheint. Es gibt noch einige weitere Elemente der OMT-Notation, die hier nicht vorgestellt werden.



Die OMT-Notation unterstützt drei Arten von Diagrammen:


(siehe dazu auch Abschnitt 2.4.1 Graphische Notation Abb. 1.1)



Jede Entwurfsmusterbeschreibung enthält ein Klassendiagramm. Andere Diagrammarten werden nach Bedarf verwendet.


4.6 Klassen- versus Schnittstellenvererbung


Es ist wichtig, den Unterschied zwischen der Objektklasse und -typ zu verstehen. Die Klasse definiert die Daten und Implementierung der Operationen eines Objekts, also wie das Objekt implementiert wurde. Der Objekttyp dagegen bezieht sich nur auf seine Schnittstelle, also auf die Menge von Anfragen auf die ein Objekt reagieren kann. Damit kann ein Objekt unterschiedliche Typen haben, und Objekte von verschiedenen Klassen


können den gleichen Typ haben. Es ist wichtig, zwischen der Klassen- und Schnittstellenvererbung zu unterscheiden. Klassenvererbung definiert Objektimplementierung aufbauend auf der Implementierung eines anderen Objekts. Es ist ein Mechanismus zur Code- und Darstellungsverteilung. Schnittstellenvererbung dagegen beschreibt, wann ein Objekt anstelle eines anderen benutzt werden kann. Die meisten Programmiersprachen unterstützen diese Unterscheidung jedoch nicht. Einige der Entwurfsmuster sind aber von dieser Unterscheidung abhängig.


4.7 Programmienen zur Schnittstelle, nicht zur Implementierung


Klassenvererbung ist ein Mechanismus, um Funktionalität von Anwendungen durch Wiederverwendung der Funktionalität von Elternklassen zu erweitern. Sie erlaubt es, sehr schnell eine neue Art von Objekten aufbauend auf vorhandenen Objekten zu definieren. Sie erlaubt Erstellung von neuen Implementierungen mit sehr geringen Aufwand, denn das meiste was man braucht erbt man von existierenden Klassen.

Jedoch ist Wiederverwendung der Implementierung nur die halbe Geschichte. Wichtig ist auch die Fähigkeit der Vererbung, Familien von Objekten mit identischen Schnittstellen zu bilden. Normalerweise wird dabei von abstrakten Klassen geerbt. Diese Fähigkeit ist so wichtig, weil Polymorphie von ihr abhängig ist. Wenn man Vererbung erfolgreich anwendet, dann teilen alle von der abstrakten Klasse abgeleitete Klassen die Schnittstelle der abstrakten Klasse. Das impliziert, daß Subklassen lediglich Operationen addieren oder überschreiben, aber sie machen nicht Operationen der abstrakten Klasse unsichtbar. Also können alle Subklassen auf die Nachrichten von der Schnittstelle der abstrakten Klasse antworten. Damit werden die Subklassen zu Subtypen der abstrakten Klasse. Es gibt zwei Vorteile Objekte ausschließlich über Schnittstellen, die bei abstrakten Klassen definiert wurden, zu manipulieren:



Dieses Vorgehen reduziert Implementierungsabhängigkeiten zwischen den Teilsystemen so stark, daß es zum folgenden Prinzip des wiederverwendbaren objektorientierten Designs führt:


Programmiere zur Schnittstelle nicht zur Implementierung !


Das ist eines der Hauptthemen der Entwurfsmuster nach Gamma et al.


4.8 Die Wiederverwendungsmechanismen arbeiten lassen


Die Entwurfsmuster können zeigen, wie man mit Hilfe von Konzepten wie Objekten, Schnittstellen, Klassen und Vererbung flexible, wiederverwendbare Software erstellen kann.



4.9 Vererbung versus Komposition


Es gibt zwei Haupttechniken, um Funktionalität in objektorientierten Systemen wiederzuverwenden. Das sind Klassenvererbung und Klassenkomposition. Die Wiederverwendung durch Bildung von Subklassen wird oft als "white-box“ Wiederverwendung bezeichnet, weil die Internas der Elternklassen für Subklassen sichtbar sind.


Objektkomposition ist eine Alternative zur Klassenvererbung. Neue Funktionalität erhält man durch Zusammensetzen (Komposition) von Objekten. Objektkomposition fordert, daß Objekte, die zusammengesetzt werden, wohldefinierte Schnittstellen haben. Diese Art der Wiederverwendung wird "black-box“ -Wiederverwendung genannt, da keine internen Details der Objekte sichtbar sind.

Vererbung und Komposition haben ihre Vor- und Nachteile. Die Klassenvererbung wird statisch zur Kompilierzeit definiert und ist einfach zu verwenden, seit sie direkt von den Programmiersprachen unterstützt wird. Die Klassenvererbung erlaubt es existierende Implementierung durch Wiederverwendung einfacher zu modifizieren. Klassenvererbung hat aber auch einige Nachteile.


  1. Man kann die von den Elternklassen geerbte Implementierungen nicht zur Laufzeit ändern, weil Vererbung zur Kompilierzeit definiert wird.

  2. Und das ist das schlimmere Problem, die Elternklassen definieren wenigstens zum Teil, die physikalische Darstellung deren Subklassen. Damit ist die Subklasse von den Details der Implementierung ihrer Elternklasse abhängig. Vererbung verletzt die Kapselung von Objekten. Das führt dazu, daß jede Änderung der Elternklasse eine Änderung der Subklassen nach sich zieht. Diese Abhängigkeit verringert Flexibilität und Wiederverwendung. Eine Lösung dafür wäre, nur von abstrakten Klassen zu erben.

Objektkomposition wird dynamisch zur Laufzeit durch Verweise auf andere Objekte definiert. Das zwingt Objekte die Schnittstellen von anderen Objekten zu benutzen. Da auf Objekte ausschließlich über deren Schnittstellen zugegriffen wird, wird die Kapselung nicht verletzt. Jedes Objekt kann also zur Laufzeit durch ein anderes Objekt, solange sie den gleichen Typ haben, ersetzt werden. Außerdem gibt es so gut wie keine Implementierungsabhängigkeiten, weil Implementierung ausschließlich auf Objektschnittstellen basiert. Das führt zum weiteren Prinzip des objektorientierten Designs:


Objektkomposition ist der Klassenvererbung vorzuziehen !


4.10 Delegation


Delegation ist ein Weg die Objektkomposition im Bezug auf Wiederverwendung leistungsfähiger als Vererbung zu machen. Bei der Delegation werden zwei Objekte in Behandlung einer Anfrage hineingezogen. Das angesprochene Objekt überträgt dabei Operationen zu seinem Stellvertreter. Das ist analog zu dem, wie Subklassen Anfragen an ihre Elternklassen weiterleiten. Der Hauptvorteil der Delegation ist, daß sie es erlaubt Verhaltensweisen zur Laufzeit einfach zusammenzusetzen und die Zusammensetzung zu ändern. Unser Fenster kann zur Laufzeit kreisförmig werden, einfach dadurch, daß


wir sein Rechteckexemplar durch ein Kreisexemplar ersetzen. Dies setzt voraus, daß das Rechteck und der Kreis denselben Typ besitzen. Delegation hat allerdings auch einen Nachteil, den sie mit anderen Techniken, die es erlauben flexiblere Software durch Objektkomposition zu erstellen, teilt. Dynamische hochparametrisierte (generische) Software ist schwerer zu verstehen, als statische Software. Damit ist auch Laufzeit-Ineffzienz verbunden, aber menschliche Ineffzienz hat auf lange Sicht größere Bedeutung. Delegation ist ein gutes Design, solange sie mehr vereinfacht als verkompliziert. Es ist nicht einfach, Regeln anzugeben, die Ihnen exakt sagen, wann man Delegation anwenden sollten, weil ihre Effektivität vom jeweiligen Kontext sowie Ihrer Erfahrung mit diesem Ansatz abhängt.


Sie funktioniert am besten, wenn sie durch Standard-Entwurfsmuster zum Einsatz kommt. Delegation ist ein extremes Beispiel für Objektkomposition. Sie zeigt, daß man Vererbung als Wiederverwendungsmechanismus von Code immer durch Objektkomposition ersetzen kann.



4.11 Vererbung versus parametrisierte Typen


Eine andere (nicht streng objektorientierte) Technik zur Wiederverwendung von Funktionalität sind generische Typen (parametrized types). Das sind z.B. Schablonen (templates) in C++ oder generics in Ada oder Eiffel. Diese Technik erlaubt Definition eines Typs ohne Spezifikation von Typen, die dieser Typ benutzt. Die unspezifizierten Typen werden dann an der Stelle der Benutzung als Parameter eingesetzt. Der wichtige Unterschied zu den anderen Techniken besteht darin, daß die generischen Typen es erlauben, die Typen zu wechseln, die eine Klasse benutzen kann, aber sie können sich nicht während der Laufzeit ändern. Keiner der Entwurfsmuster von Gamma et al. konzentriert sich auf generische Typen, aber sie werden zur Implementierung der Muster in C++ verwendet.


4.12 Beziehungen unter Laufzeit- und Kompilierzeit-strukturen


Laufzeitstrukturen von objektorientierten Programmen haben oft nur wenig Ähnlichkeit mit ihren Codestrukturen. Die Codestrukturen werden zur Kompilierzeit eingefroren. Sie bestehen aus Klassen in festen Vererbungsbeziehungen. Laufzeitstrukturen bestehen dagegen aus sich schnell änderten Netzwerken von kommunizierenden Objekten. Diese Strukturen sind tatsächlich weitgehend voneinander unabhängig. Objektaggregation und

-assoziation manifestieren sich unterschiedlich zur Kompilier- und Laufzeit.


Aggregation impliziert, daß ein Objekt ein Objekt besitzt oder verantwortlich für ein anderes Objekt ist. Man sagt, ein Objekt ist ein Teil von einem anderen Objekt. Die Aggregation impliziert weiterhin, daß ein aggregiertes Objekt und sein Besitzer die gleiche Lebensdauer besitzen.


Assoziation impliziert lediglich, daß ein Objekt ein anderes Objekt kennt. Assoziierte Objekte müssen auf Anfragen antworten, aber sie sind nicht für andere Objekte verantwortlich. Assoziation ist eine schwächere Beziehung im Vergleich zur Aggregation


und suggeriert eine schwache Kopplung zwischen Objekten. Aggregation und Assoziation sind leicht zu verwechseln, weil sie oft auf die gleiche Weise implementiert werden. Variablen sind in Smalltalk Verweise auf andere Objekte. In der Programmiersprache gibt es keine Unterscheidung zwischen Aggregation und Assoziation.


In C++ kann Aggregation in Form von Variablen, die existierende Instanzen sind, implementiert werden, es wird aber vorgezogen, sie als Zeiger oder Verweise auf Instanzen zu definieren. Assoziation kann nur mit Zeigern oder Verweisen implementiert werden. Assoziation und Aggregation drücken sich eher im Verhalten als in expliziten Sprachstrukturen aus. Der Unterschied in der Kompilierzeitstruktur ist allerdings schwer zu erkennen.


4.13 Entwerfen für Änderungen


Wenn man Wiederverwendung maximieren will, muß man in der Zukunft liegende neue Anforderungen und Änderungen an vorhandene Anforderungen voraussehen können, und dann den Systementwurf so gestalten, daß er dementsprechend erweitert werden kann. Um ein System robust gegen Änderungen zu machen, muß man sich überlegen, welche Veränderungen am System während des Einsatzes vorgenommen werden müßten. Ein Entwurf, der keine Änderungen voraussieht, riskiert einen kompletten Neuentwurf in der Zukunft. Änderungen durch Neuentwurf verursachen Neudefinition und -implementierung von Klassen, Klientmodifizierung und erneuten Test. Neuentwurf beeinflußt viele Teile des Softwaresystems und unvorhergesehene Änderungen sind sehr teuer. Entwurfsmuster können helfen einen Neuentwurf zu vermeiden, indem sie dafür sorgen, daß das System auf spezifischen Wegen geändert werden kann. Jedes Entwurfsmuster läßt irgendein Aspekt der Systemstruktur weitgehend unabhängig von anderen Aspekten. Das macht die Systemstruktur gegen Teiländerungen robuster. Es folgt eine Liste mit Hauptursachen für ein Neuentwurf:



Entwurfsmuster erlauben unterschiedliche Flexibilität, die in Software eingebaut werden kann. Wie wichtig solche Flexibilität ist, hängt von der Art der Software ab, die man entwickelt. Welche Rolle die Entwurfsmuster bei der Entwicklung von unterschiedlichen Arten von Software spielen, wird in den folgenden Abschnitten beschrieben.




4.14 Anwendungen


Beim Entwurf von Anwendungen genießen interne Wiederverwendbarkeit, Wartbarkeit und Erweiterbarkeit eine hohe Priorität. Interne Wiederverwendbarkeit garantiert, daß nur


das entworfen und implementiert wurde, was man haben wollte. Entwurfmuster, die Abhängigkeiten reduzieren, erhöhen interne Wiederverwendbarkeit.


Entwurfsmuster machen die Anwendung wartbar, wenn sie eingesetzt werden, um deren Systemabhängigkeit zu reduzieren. Sie steigern Erweiterbarkeit, wenn sie zeigen, wie Klassenhierarchie erweitert und Objektkomposition abgebaut werden kann. Reduzierte Kopplung erhöht Erweiterbarkeit.


Toolkits sind Bibliotheken mit vordefinierten Klassen. Das sind also Sammlungen von wiederverwendbaren und in Relation zueinander stehenden Klassen, die allgemeinverwendbare Funktionalität bieten. Toolkits erzwingen kein spezielles Design, sondern bieten grundlegende Funktionalität an, die vom Programmierer ohne erneute Codierung übernommen werden kann. Toolkits sind damit das objektorientierte Äquivalent zu Funktionsbibliotheken.

Ein Toolkit ist im Vergleich zu einer Anwendung wesentlich komplexer zu entwerfen, weil es in vielen Anwendungen sinnvoll einsetzbar sein soll, die speziellen Bedürfnisse der Anwendungen aber zu diesem Zeitpunkt nicht bekannt sind. Das macht es so wichtig die Annahmen und Abhängigkeiten, die die Flexibilität, Anwendbarkeit und Effizienz des Toolkits einschränken, zu umgehen.


4.15 Wie findet man das richtige Entwurfsmuster


Erich Gamma et al. geben folgende Ansätze, um passende Entwurfsmuster für ein spezielles Entwurfsproblem zu finden:




(siehe dazu auch Abschnitt 2.5 Klassifizierung der Entwurfsmuster Abb. 2.1)




4.16 Wie benutzt man Entwurfsmuster?


Gamma et al. geben folgende Schritt für Schritt Anleitung, wie man die Entwurfsmuster effektiv anwenden kann:


  1. Man lese das Muster einmal durch, um eine Übersicht zu erlangen.

  2. Man schenke besondere Aufmerksamkeit den Anwendbarkeits- und Konsequenzenabschnitten, um festzustellen ob es das richtige Muster für das Problem ist.

  3. Man kehre zurück und studiere die Struktur-, Teilnehmer- und Zusammenhang Abschnitte. Man überzeuge sich, daß man die Klassen und Objekte sowie deren Beziehungen verstanden hat.

  4. Man sehe sich die konkreten Codebeispiele des Musters im Beispielcodeabschnitt an. Dabei lernt man, wie das Muster implementiert wird.

  5. Man wähle im Anwendungskontext ausdrucksstarke Namen für Musterteilnehmer, weil die Teilnehmernamen bei den Entwurfsmustern einfach zu abstrakt sind, um sie direkt in den Anwendungen einzusetzen.

5. Das Model - View - Controller Entwurfsmuster (MVC)

Ein Beispiel für die Anwendung von Entwurfsmustern:



Abb. 5.1 MVC - Entwurfsmuster


Wir möchten jetzt anhand eines Beispieles die Entwurfsmusteridee präsentieren. Das MVC Entwurfsmuster ist ein Teil der Programmiersprache, Smalltalk-80. Es besteht aus drei abstrakten Klassen. Diese Klassen kooperieren miteinander, um die Datenmenge eines Datensatzes in unterschiedlichen Sichten darstellen zu können.




MVC besteht aus drei Arten von Objekten.



Vor MVC war es üblich, diese drei Komponenten zusammen zu koppeln. Die Entwurfsphilosophie des MVC entkoppelt diese drei Objekte, um die Flexibilität und die Wiederverwendbarkeit zu erhöhen.


MVC entkoppelt Präsentationen und Anwendungen, indem zwischen ihnen ein Kommunikationsprotokol eingeführt wird. Eine Präsentation Muß sicherstellen, daß ihre Darstellung den momentanen Zustand der Anwendung reflektiert. Bei jeder Veränderung des Dateneingangs in einer Anwendung werden alle aktive Präsentationen, die mit diesem Dateneingang im Zusammenhang stehen, benachrichtigt.


Das bewirkt, daß jede Präsentation aktualisiert wird. Dieser Entwurfsansatz erlaubt es Ihnen , mehrere View - Objekte zu erzeugen, um mehrere Präsentationen auf dem Bildschirm zu erzeugen. Das betrifft nicht nur 'Flexibilität sondern auch die Wiederverwendbarkeit dieses Musters. Man kann immer wieder neue View-Objekte zu dem System hinzufügen, ohne auch nur eine Zeile von dem vorhandenen Code zu ändern.




Eine formelle Beschreibung des MVC Musters sieht folgendermaßen aus:


Name:


Modell - View - Controller


Problem:


Adaptierbare GUI. Die Oberfläche einer Anwendung soll an kundenspezifische Bedürfnisse anpaßbar sein. Zum Beispiel möchte Sie unterschiedliche Standards wie Motif oder Open-Windows unterstützen. Auch könnte es nötig sein, für verschiedene Benutzer unterschiedliche Modi bereitzustellen, z. B. für die Benutzer Administrator und Datentypist. Im Unterschied zu dieser hohen Flexibilität soll der funktionale Kern der Software unverändert bleiben.


Insbesondere sollen bei der Entwicklung folgende Faktoren berücksichtigt werden:



Lösung:


Das Hauptprinzip des Model View Controller - Entwurfsmusters ist die Trennung der Verantwortlichkeiten. Man trennt die Kernfunktionalität der Anwendung von der Darstellung der Information und der Verarbeitung der Benutzereingaben. Dies führt zu einer Struktur mit drei Subsystemen: Model, View, und Controller



Implementierung dieses Mechanismus kann man das Beobachter Entwurfsmuster aus [Gam96] verwenden. Dabei wird das Modell als Publisher tätig und propagiert Änderungen an alle negistrierten View- und Controller Objekte.


Konsequenzen:


Folgende Vorteile ergeben sich aus der Strukturierung eines Systems nach dem Model View-Controller Architekturmuster


Beim Einsatz von MVC sind aber auch einige Schwierigkeiten zu beachten



6. Zusammenfassung


Entwurfsmuster sind eine vielversprechende Technologie zur produktiven Erstellung großer und industrieller Softwaresysteme mit definierten Eigenschaften. Während Methoden, wie die Booch-Methode oder OMT, eine allgemeine Vorgehensweise zur Erstellung von Softwaresystemen definieren, adressieren Entwurfsmuster ganz spezielle, nur in einem bestimmten Kontext auftretende Entwurfsprobleme und erlauben Konstruktion von auf konkrete Bedürfnisse und Anforderungen zugeschnittenen Softwarearchitekturen.


Eine andere interessante Beobachtung ist, daß die Konstruktion von Software mit Entwurfsmustern ein evolutionärer Ansatz für die Softwareentwicklung ist, nicht aber ein kompositioneller. Es ist kein Prozeß in dem vorgefertigte Teile zusammengesteckt werden und dann ein Ganzes bilden. Es ist vielmehr ein Prozeß des Entfaltens, der Differenzierung und Verfeinerung von gegebenen Strukturen, in dem das Ganze den einzelnen Teilen vorangeht. Dieser Prozeß erfolgt schrittweise, beginnend mit Entwurfsmustern zur Festlegung der Grundarchitektur einer Anwendung, gefolgt von Entwurfsmustern zur weiteren Gestaltung von Komponenten und Beziehungen zwischen Komponenten, und endend mit Entwurfsmustern für die konkrete Realisierung bestimmter Entwurfsaspekte. Desweiteren werden Entwurfsmuster nicht erfunden oder künstlich konstruiert. Vielmehr werden sie aus existierender wohlerprobter Entwurfspraxis abgeleitet.

Literaturverzeichnis


[AIS77] Christopher Alexander, Sara Ishikawa, Murray Silverstein.

A Pattern Language. 11. Aufl., New York: Oxford University Press, © 1977


[Alex79] Christopher Alexander.

The Timeless Way of Buildin, New York: Oxford University Press, © 1977


[Brockhaus91] Brockhaus-Enzyklopädie in 24 Bänden, 18.Aufl.

Mannheim: Brockhaus GmbH, Seite 246-247, © 1991


[Duden89] Duden - Deutsches Universalwörterbuch,2. Aufl.

Mannheim: Bibliographisches Institut, Seite 1046, © 1989


[Gam95] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides

Design Patterns, Elements of Reusealbe Object-Oriented Software. 5. Aufl.

Reading, MA: Addison-Wesley Publishing Company, © 1995


[Gam96] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides

Entwurfsmuster. Addison-Wesley Publishing Company, © 1996


[Mey90] Bertrand Meyer

Introduction to the Theory of Programming Languages.

Prentice Hall, © 1990


[Nico96] Nicolay Hombach

Hardware-Entwurfsmuster am Beispiel des Boundary-Scan

(http://www.ti-et.inf.uni-siegen.de/Diplom/NHombach/nh-pages/nhdipde.html)


Copyright © 1997 Fachbereich 12 Technische Informatik
Letzte Änderung: 05.04.1999 von René Eßer