\newpage
\section{Verwendung von Entwurfsmustern}\label{Entwrfsmstr}In verschiedenen
Ver"offentlichungen wurde in letzter 
Zeit der Einsatz von Entwurfsmustern ({\em design patterns}) in der
objektorientierten Softwareentwicklung diskutiert und entsprechende
Mustersammlungen vorgestellt \cite{Gamm95,Pree95}.

Die Entwurfsmuster dieser Sammlungen beruhen auf den bei der Entwicklung von
gro"sen objektorientierten Systemen gemachten Erfahrungen. Mit der Beschreibung
von Entwurfsmustern wird versucht, L"osungen f"ur 
bestimmte immer wieder auftretende Problemstellungen als Schema zu erfassen,
da"s hei"st den Kern des L"osungsansatzes darzustellen und zu benennen. Gelingt
dies, so k"onnen sie von anderen Entwicklern genutzt werden, um in "ahnlichen
Situationen die gleiche Technik einzusetzen. Der Entwickler kann das Muster in
seinen Kontext "ubernehmen und seine Entwurfsentscheidungen auf
einem abstrakteren Niveau "uberdenken. Die allgemeine Formulierung solcher
L"osungsans"atze macht sie austauschbar.

Die Beschreibungen von Entwurfsmustern
beruhen meist auf der Darstellung von Beziehungen zwischen Objekten und
Klassen. 
Die Problemsituation geschildert, die L"osung skizziert und mit
Beispielen verdeutlicht. Entwurfsmuster werden sowohl zur Verdeutlichung von
systemspezifischen Entwurfsentscheidungen, um dem Benutzer den Einstieg zu
erleichtern, als auch zur allgemeinen Darstellung von Konstruktionstechniken
eingesetzt.

Im folgenden werden einige Entwurfsmuster vorgestellt und
anschlie"send ihre Anwendung in der Beh"alterklassenbibliothek von TooL
diskutiert.
\subsection{Br"uckenklassen}\label{BrKlss} Das Entwurfsmuster {\em Bridge} oder Br"uckenklasse
\cite[S.151ff]{Gamm95} beschreibt eine Technik 
zur Entflechtung von Implementierung und Abstraktion. Werden verschiedene
Implementierungen f"ur eine Abstraktion als Subklassen realisiert, so f"uhrt
dies bei einer Verfeinerung der Abstraktion zu entsprechend vielen Nachkommen
der Verfeinerung, welche die Implementierungsvarianten umsetzen. Umgekehrt
bewirkte die Einf"uhrung einer neuen Implementierungsform, da"s diese f"ur die
Abstraktion selbst und f"ur jede Verfeinerung der Abstraktion umgesetzt werden
mu"s. 
Die Br"uckentechnik kann diese Situation vereinfachen und eine separate
Verfeinerung f"ur beide Seiten erm"oglichen. Weiterhin kann unter anderem der
Implementierungswechsel zur Laufzeit bzw. eine automatische
Implementierungswahl erreicht werden.

%%%%%%%%%Bild: Bridge
\renewcommand{\epsfsize}[2]{0.789#1}
\begin{figure}[hbt]
\begin{center}
\leavevmode
%\epsfysize=8cm
\epsffile{../Bilder/bjoern/DPBridge.ps}
\end{center}
\caption{Entflechtung von Implementierung und Abstraktion: Br"uckenbildung
\protect{\linebreak[4](aus [\mbox{Gamma} et al.,S.153])}}\label{BridgeFig}
\end{figure}

Grundidee f"ur die Br"uckenbildung ist
die Definition eines abstrakten Implementierungsprotokolls durch eine separate
Implementierungsklasse. Die Nachfolger dieser Klasse realisieren dann dieses
Protokoll f"ur unterschiedliche Varianten der Repr"asentation. Mit Hilfe dieses
Protokolls kann nun eine Br"ucke zu der eigentlichen Abstraktion geschlagen
werden. Diese nutzt es, um ihre Methoden (teilweise) zu implementieren. Um eine
konkrete Implementierung zuordnen zu k"onnen, wird eine Variable f"ur ein
solches Implementierungsobjekt eingef"uhrt. "Uber diese wird das abstrakte
Implementierungsprotokoll angesprochen, soda"s bei einer anderen
Anfangsbelegung oder einem Austausch des Objekts die jeweilige konkrete
Implementierung verwendet 
wird. In Abbildung \ref{BridgeFig} wird das Verfahren skizziert.

Die Nutzung des abstrakten Implementierungsprotokolls ist entscheidend f"ur die
einfachere Erg"anzung weiterer Verfeinerungen oder
Implementierungsvarianten. Werden statt dessen direkte
Br"uckenklassen\footnote{Eine spezielle Klasse, welche die durch die
Abstraktion spezifizierten Methoden mit Bezug auf eine konkrete
Implementierungsklasse realisiert.} zur 
Verbindung von Abstraktion und Implementierungsvariante
genutzt \cite[S.64]{Tr95}, so mu"s bei einer Verfeinerung erneut f"ur
jede Variante eine Br"ucke hergestellt werden. Diese degenerierte
Br"uckentechnik \cite[S.160]{Gamm95} unterst"utzt also gerade nicht
die Verfeinerung auf beiden Seiten der Br"ucke.

\subsection{Fabrikklassen}\label{Fbrkklss}Das Entwurfsmuster {\em abstract
factory} \cite[S.87ff]{Gamm95} generalisiert die Erzeugung von Objekten.

%%%%%%%%%Bild: Factory
\renewcommand{\epsfsize}[2]{0.789#1}
\begin{figure}[htb]
\begin{center}
\leavevmode
%\epsfysize=8cm
\epsffile{../Bilder/bjoern/DPFactory.ps}
\end{center}
\caption{Kontextbezogene Objekterzeugung: Abstrakte Fabrik (nach [\mbox{Gamma} et al. 95, S.88])}\label{FactoryFig}
\end{figure}

Eine abstrakte Fabrikklasse definiert eine Schnittstelle mit Erzeugungsmethoden
f"ur zusammengeh"orige oder abh"angige Familien von Objekten. Konkrete
Nachfolger dieser Klasse repr"asentieren familien"ubergreifende gleichartige
Erzeugungsverfahren und implementieren die Methoden in diesem Kontext. Diese
Nachfolger k"onnen dann genutzt werden, um die Objekte der einzelnen Familien
kontextabh"angig zu erzeugen.

F"ur einen Klienten bedeutet dies, da"s er sich
durch einmalige Wahl der 'richtigen' Fabrik versichern kann, immer die
korrespondierende Objektvariante aus den verschiedenen Familien zu
erhalten. Er kann von der kontextspezifischen Erzeugung abstrahieren, da diese
von der Fabrik geleistet wird. Ein Kontextwechsel kann au"serdem einfach durch
Austausch der Fabrik erfolgen.

In Abbildung \ref{FactoryFig} ist die Technik skizziert. 
Die beiden abstrakten Klassen {\sf ProduktA} und {\sf ProduktB} beschreiben
zwei Objektfamilien, f"ur deren Nachfahren {\sf VarianteA1} und {\sf
VarianteB1} sowie {\sf VarianteA2} und {\sf VarianteB2} eine Verbindung durch
ihr Auftreten 
in einem gemeinsamen Kontext besteht. Ein solcher Kontext k"onnte zum Beispiel
die Plattformabh"angigkeit von bestimmten Objekten sein. In der Klasse
{\sf \mbox{AbstrakteFabrik}} werden Methoden zur Erzeugung von Objekten beider
Familien 
eingef"uhrt. Die Klasse {\sf KonkreteFabrik1} beispielsweise definiert diese
Methoden dann so, da"s jeweils die Variante eins der Objektfamilien A und B
generiert wird.

Nachteilig f"ur die Erweiterbarkeit ist die Spezifizierung einzelner
Erzeugungsmethoden f"ur jede Objektfamilie. Bei Einf"uhrung weiterer
Objektfamilien m"ussen entsprechende Erzeugungsmethoden erg"anzt werden, was
dann zur "Anderung aller kontextbezogenen Nachfolger der abstrakten Fabrik
veranla"st. Vermeidbar ist dieses Problem durch Verwendung eines Parameters,
mit dem die zu erzeugende Objektart festgelegt wird. Es wird dann nur noch eine
Erzeugungsmethode ben"otigt. F"ur statisch typisierte Sprachen ist diese
Variante generell nur einsetzbar, wenn die beteiligten Objektfamilien eine
gemeinsame Oberklasse haben. Dann besteht die Gefahr, da"s nur Objekte mit dem
gemeinsamen abstrakten Protokoll dieser Oberklasse erzeugt werden und
Spezialisierungen f"ur Klienten nicht mehr sichtbar sind
\cite[S.91]{Gamm95}. Durch den Einsatz von  
Typparametern, wie dies in TooL m"oglich ist, bleibt die Fabriktechnik aber
auch dort einsetzbar. Die Fabriken k"onnen bei ihrer Erzeugung so instantiiert
werden, da"s die gew"unschte Spezialisierung mit vollzogen wird. Dies wird auch
in den Beispielen des n"achsten Abschnittes deutlich werden.
\subsection{Anwendung} Im folgenden soll die Umsetzung der beiden vorgestellten
Entwurfstechniken {\em Br"ucke} und {\em AbstrakteFabrik} f"ur die
Beh"alterklassenbibliothek von TooL anhand eines Beispiels demonstriert und
diskutiert werden.

Der Zielsetzung der Br"uckentechnik entsprechend liegt es
f"ur die Beh"alterklassen nahe, unterschiedliche Implementierungsvarianten
einer Beh"alterkategorie auf diese Weise zu realisieren. Solche Varianten
wurden bisher in der Beh"alterbibliothek von TooL als spezielle Eigenschaften
einer solchen Kategorie interpretiert, wie dies am Beispiel der Listen in
Abbildung \ref{ListenFig} deutlich wird. Die Definition einer weiteren
Implementierungseigenschaft {\sf ArrayedList}, die f"ur alle Varianten
realisiert werden soll, w"urde zur Definition eines Teilgraphen von Klassen
f"ur die Kombination mit den anderen speziellen Eigenschaften f"uhren. Durch
die Anwendung der Br"uckentechnik kann der Aufbau dieses Teilgraphen eingespart
werden, wenn man f"ur das abstrakte Implementierungsprotokoll eine weitere
Subklasse definiert, die dieses Protokoll "uber ein {\sf Array} realisiert.

%%%%%%%%%Bild: ListenNeu
\renewcommand{\epsfsize}[2]{0.789#1}
\begin{figure}[hbt]
\begin{center}
\leavevmode
%\epsfysize=8cm
\epsffile{../Bilder/bjoern/DPListsNeu.ps}
\end{center}
\caption{Listen mit separater Repr"asentationsimplementation}\label{ListenFigNeu}
\end{figure}

Die
Beh"alterkategorie der Listen kann dann in der in Abbildung \ref{ListenFigNeu}
gezeigten Form definiert werden.
Waren in der alten Version noch die
Kombinationen mit den Implementierungseigenschaften zur besseren
"Ubersichtlichkeit nicht abgebildet, so ist hier bereits die gesamte
Listenkategorie zu sehen. Der Graph wird flacher. In den Listenklassen
sind nun alle Methoden mit Hilfe 
des abstrakten Protokolls aus {\sf ListImplementor} realisiert. Auch die
Wurzelklasse ist bereits instantiierbar. Sie definiert jetzt eine Variable {\sf
impl} zur Verwaltung der aktuellen Implementierungsform.
Der Typ dieser Variablen wird durch die Wurzelklasse der
Listenimplementierungen spezifiziert. Dies verlangt die Einhaltung der
Subtypbeziehung innerhalb der Hierarchie von Implementierungsvarianten. Soll
auch hier die spezialisierende Vererbung von Methoden mit Objekttypparametern
eingesetzt werden, so k"onnen solche Imlementierungen durch die Einf"uhrung
eines weiteren Typparameters f"ur die Klasse {\sf List}, der den
Implementierungstyp beschreibt, genutzt werden.

Dadurch, da"s in der
Listenhierarchie von der Art der Repr"asentation abstrahiert wird, tritt eine
diesbez"ugliche Implementierungsvererbung dort nicht mehr auf. Die
Implementierungshierarchie ist prinzipiell flach angelegt, da die einzelnen
Varianten nebeneinander stehen. Generell ist aber hier auch eine Verfeinerung
m"oglich, soda"s diese Art der Vererbung dort wieder auftreten kann.
Auf der Listenseite bleibt weiterhin auch die Vererbung von nicht
repr"asentationsbezogenen Implementierungen bestehen.

Das von der Klasse {\sf
ListImplementor} angebotene Protokoll mu"s so m"achtig sein, da"s alle
Listenmethoden der verschiedenen Listenvarianten damit implementierbar sind und
die jeweiligen Vorteile der Repr"asentationsstrukturen auch zum Tragen kommen.
Im Prinzip wird also durch diese Klasse bereits eine alle Eigenschaften
vereinigende Liste
spezifiziert, deren M"achtigkeit dann durch die eigenschaftsbezogenen Varianten
der Listenhierarchie wieder gekapselt wird. Diese Beobachtung  k"onnte dazu
verleiten, bereits die Wurzelklasse mit der gesamten Funktionalit"at
auszustatten bzw. die Aufteilung des Listenprotokolls erst gar nicht
vorzunehmen. Damit enfallen aber die M"oglichkeiten, die eine solche
Aufteilung mit sich bringt: das eigenschaftsbezogene Ausw"ahlen, die
vereinfachte Sicht auf komplizierte Objekte und die Kombination mit neuen
Eigenschaften unter Vermeidung von inkompatiblen Protokollgruppen. Die
skizzierte L"osung verkn"upft diese Vorteile mit den oben dargelegten, der
Br"uckentechnik zuzuordnenden Verbesserungen.

Etwas problematisiert wird die
Erzeugung von Listenobjekten. Die auf die Implementierung verweisende private
Variable mu"s belegt und damit die Entscheidung f"ur eine
Implementierung gef"allt werden. Verschiedene L"osungsans"atze sind
denkbar. Die Entscheidung kann intern getroffen werden, sollte aber f"ur die
Listenbeh"alter vom Benutzter beeinflu"sbar sein, um die Wahl der
effizientesten Elementstruktur dem der Liste zugedachten Einsatzbereich
anzupassen. Die Belegung der privaten Variable kann in TooL nur durch
Subklassen oder mit Hilfe von Methodenaufrufen erfolgen. Subklassenbildung
entspricht der  
Bildung von direkten Br"uckenklassen zu den Implementierungsvarianten und ist
daher aus den bereits unter \ref{BrKlss} aufgef"uhrten Gr"unden
abzulehnen.

G"unstig w"are es, die Entscheidung f"ur eine Implementierungsvariante gleich
bei der Erzeugung treffen 
zu k"onnen. Methoden zur Erzeugung von Objekten einer Klasse werden in TooL in
der Metaklasse dieser Klasse definiert. Diese braucht dann aber den Zugriff auf
die Implementierungsvariable. Es wird deshalb eine Methode zur Zuweisung der
Implementierung der durch {\sf List} spezifizierten Objektschnittstelle
hinzugef"ugt. In der Metaklasse erh"alt die Methode {\sf new} nun einen
Parameter, auf dem die gew"unschte Implementierung "ubergeben werden kann. Auch
alle anderen Erzeugungsmethoden ben"otigen diesen Parameter.

Die Erzeugung der verschiedenen Implementierungsvarianten der Listen kann
allerdings auch mit Hilfe der unter \ref{Fbrkklss} geschilderten Fabriktechnik
durchgef"uhrt werden.
Die Adaption des Schemas mit Objektfamilien und
kontextabh"angiger Erzeugung kann folgenderma"sen geschehen. Als Objektfamilie
k"onnen die mit verschiedenen konkreten Implementierungen ausgestatteten
Listenobjekte einer bestimmten Listenvariante betrachtet werden. Also z.B. die
Array- oder Kettungsimplementierungen einer positionierbaren Liste. Jeder
Variante 
sind entsprechende Objekte zuzuordnen\footnote{Diese Objekte k"onnen auch als
Objekte der nicht definierten direkten Br"uckenklassen jeder Listenvariante
interpretiert werden.} und jede Variante kann daher als eigenst"andige
Objektfamilie betrachtet werden. Als gemeinsamer Kontext wirken die
verschiedenen Implementierungen als Array, oder unter Verwendung einfach
bzw. doppelt verketteter Zellen. Es ist also die Erzeugung verschiedener
Listenvarianten in dem gemeinsamen Kontext, da"s zum Beispiel eine
Arrayimplementierung ben"otigt wird, zu modellieren.

Abbildung \ref{LstnFbrk}
zeigt die entsprechende Listenfabrik. Sie f"uhrt Typparameter zur Anpassung des
R"uckgabetyps der Erzeugungsmethoden ein, wie schon unter 
\ref{Fbrkklss} angedeutet.

%%%%%%%%%Bild: ListenFabrik
\renewcommand{\epsfsize}[2]{0.789#1}
\begin{figure}[htb]
\begin{center}
\leavevmode
%\epsfysize=8cm
\epsffile{../Bilder/bjoern/DPListFactory.ps}
\end{center}
\caption{Erzeugung von Listenvarianten: Listenfabriken}\label{LstnFbrk}
\end{figure}

Bei der Erzeugung einer Listenfabrik mu"s der Typ der zu erzeugenden
Listenvariante "ubergeben werden. Die Fabrik ist dann auf diese Variante
zugeschnitten. Die Implementierungsart kann nun explizit durch die Wahl der
entsprechenden Fabrikklasse f"ur die gew"unschte Form festgelegt werden.

Jeder Erzeugungsmethode m"u"ste eigentlich eine konkrete Klasse des richtigen
Typs 
"ubergeben werden, damit diese zur Erzeugung eines Listenobjekts benutzt werden
kann. Um diesen Parameter zu vermeiden, wurde eine weitere Methode in {\sf
AbstractListFactory} eingef"uhrt welche den Produktionsvertrag der Fabrik mit
einer konkreten Listenvariante schlie"st. Diese Klasse wird auf einer privaten
Variable gespeichert und dann in den Subklassen von der Methode {\sf new} zur
Erzeugung eines Objekts dieser Klasse genutzt. Die Initialisierung der
Implementierungsvariablen des Listenobjekts erfolgt entsprechend dem
gew"unschten Implementierungskontext.

Erzeugung und Einsatz einer Fabrik k"onnen dann, wie in Abbildung \ref{Fbrktn}
zu sehen, durchgef"uhrt werden.

\begin{figure}[htb]
\begin{xple}
$|>$ \k{define} listFactory :AbstractListFactory(Int, UnsortedList(Int));
$|>$ listFactory $:=$ ArrayedListFactory.new;

a ArrayedListFactory
$|>$ listFactory.contractWith(UnsortedList);

nil
$|>$ \k{define} l :UnsortedList(Int);
$|>$ l $:=$ listFactory.list4(1,2,3,4)

a UnsortedList\{1 2 3 4\}
$|>$
\end{xple}
\caption{Fabrikation}\label{Fbrktn}
\end{figure}

Die hier realisierte Variante des allgemeinen Entwurfsmusters mit
Typparametern erlaubt es auch weiterhin, innerhalb des Anwendungsprogramms vom
Erzeugungsvorgang zu abstrahieren. Die Initialisierung mit der
Implementierungsvariante braucht nicht mehr explizit zu erfolgen.
Au"serdem werden Informationen dar"uber, welche Klasse eine solche
Implementierungsvariante spezifiziert, f"ur die Formulierung der Anwendung
nicht mehr ben"otigt. Der Name der benutzten Listenvariante taucht hier
allerdings im  Anwendungsprogramm auf. Allerdings nur im Zusammenhang mit der
Fabrikerzeugung, da er dort f"ur die Instantiierung der Typparameter ben"otigt
wird. Die Erzeugung konkreter Listen kann dann immer "uber die Listenfabrik
erfolgen. 

Durch die Verwendung der vorgestellten Techniken kann also eine flachere
Struktur und damit eine Vereinfachung des Vererbungsgraphen erreicht
werden. Das Hinzuf"ugen von weiteren Klassen 
wird durch die Trennung von Implementierung und Abstraktion erleichtert. 
Der Wechsel der Implementierungsform zur Laufzeit ist auch in der
Biliotheksversion mit gleichem Aufwand m"oglich, allerdings nicht
direkt durch den Aufruf einer Listenmethode. Es bedarf der
Erzeugung einer Liste mit der gew"unschten Implementierung, in welche
dann die Elemente mit Hilfe der {\sf Streams} eingef"ugt werden.

Ein geeignetes abstraktes Implementierungsprotokoll zu finden, kann
problematisch sein. F"allt es zu umfangreich aus, so leidet die
"Ubersichtlichkeit. Bei der Definition einer einfachen neuen Listeneigenschaft
bedeutet die Besch"aftigung mit diesem Protokoll eine unn"otige Komplizierung
f"ur den Entwickler. Bietet das Protokoll dagegen nur wenige Methoden an, dann
besteht die Gefahr, da"s die Vorteile konkreter Implementierungen nicht genutzt
werden k"onnen. Die Bindung aller Listenklassen an das abstrakte
Implementierungsprotokoll verlangt dar"uber hinaus eine fr"uhe Stabilisierung
dieser Schnittstelle. "Anderungen wirken sich auf alle Listenvarianten aus.

Die Anwendung der Fabriktechnik scheint dagegen f"ur die Beh"alterklassen keine
so gro"sen Vorteile zu bringen. Sie erspart zwar den sonst f"ur jede
Erzeugungsmethode der Metaklasse notwendigen Parameter f"ur die
Implementierungsform, dies ist aber nur f"ur Anwendungen von Belang, die
h"aufig gleichartige Objekte diesen Typs erzeugen wollen wie z.B. Fenster einer
Benutzeroberfl"ache. Bei Beh"altern ist dies nicht unbedingt zu erwarten. Es
steht eher die Arbeit mit dem Beh"alter im Fordergrund nicht so sehr seine
Erzeugung. Unter diesem Aspekt ist die zus"atzliche Erzeugung einer 
entsprechenden Fabrikklasse eine Komplizierung des Verfahrens. Weiterhin
positiv zu beurteilen ist, da"s die Implementierungsklassen im Verborgenen
bleiben, was aber auch durch entsprechende Methodenvielfalt in der Metaklasse
erreicht werden kann. 
 



