%% LyX 2.0.1 created this file.  For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[english,ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{graphicx}

\makeatletter

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
\newcommand{\noun}[1]{\textsc{#1}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\newenvironment{lyxcode}
{\par\begin{list}{}{
\setlength{\rightmargin}{\leftmargin}
\setlength{\listparindent}{0pt}% needed for AMS classes
\raggedright
\setlength{\itemsep}{0pt}
\setlength{\parsep}{0pt}
\normalfont\ttfamily}%
 \item[]}
{\end{list}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
\usepackage{multicol}

\makeatother

\usepackage{babel}
\begin{document}

\title{Design Pattern und objekt--orientierte Programmierung}


\author{Bernd Paysan}
\maketitle
\begin{abstract}
\noun{Stephen Pelc} hat auf der EuroForth ein dickes Fass aufgemacht,
und aufgerufen: ,,Standardize OOP now!{}`` In der darauf folgenden
Diskussion hat sich gezeigt, dass jeder etwas anderes unter OOP versteht,
und sich deshalb keine gemeinsame Praxis herauskristallisieren kann.
Dieser Artikel unternimmt den Versuch, da etwas Licht ins Dunkel zu
bringen. OOP ist ,,no silver bullet,`` wie \noun{Fred Brooks} schreibt,
es löst nicht das Problem, dass Programmieren schwer ist. Es ist aber
ein brauchbares Werkzeug für eine Reihe von Problemen, die man anders
noch schwerer lösen kann.
\end{abstract}
\begin{multicols}{2}


\section*{Einleitung}

Die \noun{Sapir--Whorf}--Hypothese besagt, dass man nicht denken kann,
was in der eigenen Sprache nicht ausgedrückt werden kann. Die Hypothese
wurde ursprünglich bezüglich natürlicher Sprachen aufgestellt, und
ist im Kern ein Konstrukt aus einer Zeit, in der andere Leute kulturelle
Unterschiede mit Rassismus erklärt haben%
\footnote{Das heißt, die beiden Herren wollten damit erklären, ,,warum Neger
doof sind,`` statt erst mal herauszufinden, ob das überhaupt so ist,
oder vielleicht gar nicht erklärt werden muss\ldots{}%
}. Sie gilt heute als widerlegt --- in jeder natürlichen Sprache kann
man alles ausdrücken, es ist nur manchmal umständlicher als in anderen
Sprachen. Und vor allem ist es schwieriger, sich in einer Sprache
auszudrücken, die man nur mäßig beherrscht --- das ist dann auch der
Grund, warum die beiden Herren zu ihrer Hypothese gekommen sind.

Für Programmiersprachen gilt diese Kritik aber nicht --- Programmiersprachen
sind künstlich, sie eröffnen tatsächlich einen Horizont zu einer neuen
Denkweise, nämlich wie man einen Computer programmieren kann. Das
ist etwas grundsätzlich anderes als sich mit Menschen zu unterhalten,
weshalb Computersprachen auch grundsätzlich anders strukturiert sind
als natürliche Sprachen. Die Denkweisen, die man mit einer Computersprache
erlernt, sind neu, und eröffnen deshalb tatsächlich neue Horizonte.
Die Konzepte, wie man sich in einer Computersprache ausdrückt, um
gewisse Probleme elegant zu lösen, nennt man ,,Design Pattern.``
Das war so Mitte der 90er--Jahre der Hype schlechthin, und ich habe
mir damals natürlich das Buch der ,,Gang of Four`` \cite{gof} aus
der Uni--Bibliothek ausgeliehen und gelesen. Ich habe auch das Buch
von \noun{Christopher Alexander} \cite{ca} gelesen, ein Architekt,
der das Konzept der Design Pattern im Zusammenhang mit Architektur
entdeckt und beschrieben hat (schon in den 70ern), und dessen Buch
Wegbereiter für diese Welle war --- und der sehr überrascht war, dass
plötzlich eine Menge Informatiker sein Buch gelesen haben. Design
Pattern werden durch die Möglichkeit einer Sprache vorgegeben ---
das Design--Pattern--Buch, wenn man es so nennen will, für die natürlichen
Möglichkeiten, die Forth von sich aus mitbringt, ist ,,Thinking Forth``
von \noun{Leo Brodie} \cite{tf}.

Forth ist eine sehr flexible und dynamische Sprache, man kann es in
alle möglichen Richtungen erweitern. Fügt man OOP zu Forth hinzu,
so fügt man ein anderes Programmier--Paradigma hinzu, denn Forth selbst
hat keine OOP--Fähigkeiten. Ich habe früher öfter gehört ,,Forth
braucht kein OOP, wir haben ja CREATE DOES>``. Das ist so etwa, wie
wenn man sagt ,,ich brauche keine Freundin, ich habe ja ein Fahrrad.``
Man kann mit CREATE DOES> ein OOP--System implementieren, aber es
selbst \emph{ist} kein OOP. Genauso kann man mit dem Fahrrad zu seiner
Freundin fahren, aber es \emph{ist} keine Freundin. Die Philosophen
bezeichnen so eine Antwort als ,,Kategoriefehler.`` Es ist aber
eine ganz normale Tatsache, dass man Dinge, die man nicht kennt, auch
nicht vermisst. Insofern ist es nicht verwunderlich, dass der typische
Forth--Programmierer mit CREATE DOES> und Fahrrad zufrieden ist ;-).
CREATE DOES> ist eher so etwas wie eine Closure, also das Bündeln
von Daten mit einer einzigen Funktion.

OOP verspricht, komplexe Programme wartbar zu machen. Was wir durch
OOP bekommen haben, sind riesige, schwerfällige Programme, die die
Gigahertz--CPUs des 21. Jahrhunderts zum Schwitzen bringen, und die
Terabyte--Festplatten füllen. Das ist aber kein Widerspruch, denn
Programmierer neigen dazu, ihre Programme wachsen zu lassen, bis sie
die Grenzen der Wartbarkeit erreicht haben. Im Umkehrschluss heißt
das natürlich, dass Forth--Programme nur deshalb so kompakt und schnell
sind, weil größere Programme in Forth einfach nicht mehr wartbar sind,
und die Programmierer von sich aus darauf verzichten, sie mit Features
zu überfrachten. Forth--Programmierer haben natürlich einen Ausweg
aus dem Dilemma gefunden: es ist die Unzahl verschiedener, untereinander
nicht kompatibler OOP--Erweiterungen, die auch OOP--basierte Forth--Programme
ab einer gewissen Größe unwartbar machen (zumindest für Dritte, denn
ab einer gewissen Größe braucht man Teams von Programmierern, um Programme
weiter wachsen zu lassen), also dafür sorgen, dass sie klein und schnell
bleiben.

\noun{Stephen Pelc} hat dieses Problem auf der EuroForth angesprochen,
und gefordert ,,Standardize OOP Now!{}`` Das Thema führte dann am
Ende der Konferenz noch zu zwei Workshops und nach der Konferenz zu
weiterer Diskussion per Mail, über die ich hier ausführlicher berichte:
\noun{Andrew Haley} bringt dazu zwei Sachen ins Spiel: Zum einen die
,,Design Patterns,`` deren Implementierung mit einem brauchbaren
OOP möglich sein muss, zum anderen das Metaobject Protocol \cite{mop},
mit dem die Common--Lisp--Leute ihr sehr ähnliches Problem gelöst
haben (auch dafür gab es einen ganzen Sack voller untereinander inkompatibler
OOP--Erweiterungen), und ein Paper, das einen interessanten Ansatz
zur Verallgemeinerung bringt. Stephen gefällt Forth meets Smalltalk
von \noun{Doug Hoffman,} er möchte das als Basis verwenden.

Stephen verkennt mit seinem Vorschlag, dass gerade \noun{Doug Hoffman}
zentrales Teil des Problems ist (auch wenn FMS nicht mehr so grauenhaft
ist wie der Vorgänger Neon). Die Diskussion darüber ging dann auch
noch per E--Mail nach dem Meeting weiter, wobei \noun{Klaus Schleisiek
Manfred Mahlows} OOP als ,,Lösung`` anpries, und seine völlige Unkenntnis
über Late Binding und vtables offenbarte. Genau das ist meiner Meinung
nach das zentrale Kern--Problem von OOP in Forth: Zu viele Leute verstehen
darunter lediglich Strukturen mit einem Namensraum für Funktionen.
Nein, OOP ist ein ganzer Sack verschiedener Konzepte, weshalb es eben
\emph{nicht} ausreicht, mal eben 10\% davon zu implementieren, denn
die 10\%--Lösungen, die alle jeweils unterschiedliche 10\% berücksichtigen,
die haben wir ja schon. Leon Wagner bestätigt diese These, denn seiner
Meinung nach ist SWOOP völlig ausreichend, auch wenn es bei Late Binding
ebenso unbrauchbar ist. Das Argument, das man immer hört, ist ,,wir/unsere
Kunden schreiben damit ernsthafte Programme.`` Nein, das ist nicht
die richtige Antwort, weil sich die Situation derzeit wohl so darstellt,
dass jedes System eben seine eigenen Stärken und Schwächen hat, und
deshalb für die zugehörige Anwendung maßgeschneidert ist --- damit
aber nicht durch ein beliebiges anderes ersetzt werden kann.

Ich habe mich jedenfalls mit ein paar Büchern eingedeckt, und denke
jetzt erst mal darüber nach, wie man das Problem richtig löst. Code
haben wir genug geschrieben, es ist jetzt Zeit, den wieder wegzuwerfen,
und das inzwischen Gelernte anzuwenden --- oder, wenn da Defizite
vorhanden sind, Neues zu lernen. Man muss sich auch im Klaren sein:
Die bisher benutzten Systeme werden nicht verschwinden, ihre Syntax
und Semantik wird erhalten bleiben. Andrews Vorschlag, ein erweiter-
und modifizierbares Grundgerüst zu nehmen, auf dem man dann verschiedene
Syntax und Semantik aufbauen kann, scheint mir der einzige brauchbare
Ansatz zu sein. Solange ich aber von meinen Mit--Forthern beim Wort
,,vtable`` immer ein ,,das ist mir zu komplex`` höre, habe ich
Bedenken --- das dabei entstehende System wird dann bestimmt als eierlegende
Wollmilchsau angesehen, und der Forth--Philosophie widersprechend,
wird also auch nicht akzeptiert.


\section{Instanz--Variablen, Methoden, Vererbung und Polymorphismus}

Die drei Grundkonzepte von OOP sind Instanz--Variablen, Polymorphismus
und Vererbung. Der Satz ,,Ein Objekt besteht aus Variablen und Methoden,
die auf diese Variablen zugreifen`` scheint überall angekommen zu
sein, das ist der gemeinsame Minimal--Konsens, es ist das Verständnis
einer um Funktionen erweiterten Datenstruktur, es ist aber nur ein
Teil dessen, was OOP ausmacht. Ebenso Konsens scheint über die Fähigkeit
zur Vererbung zu bestehen, also dass man diese Strukturen und Methoden
nachträglich erweitern kann, wodurch eine Unterklasse entsteht, der
zusätzliche Instanz--Variablen hinzugefügt werden können, und die
die Methoden der Basisklasse überschreiben kann, wobei ,,überschreiben``
bedeutet, dass die veränderten Methoden nur für die Unterklasse gelten.
Die in der Basisklasse verankerten und damit allen Unterklassen gemeinsamen
Methoden nennt man ,,Interface,`` das ist eine Kollektion von \foreignlanguage{english}{Messages},
die man den Objekten schicken kann (man sendet eine \foreignlanguage{english}{Message}
an ein Objekt, aufgerufen wird dann eine Methode --- \foreignlanguage{english}{Message}
und Methode sind zwei verschiedene Sachen, der Operator, um eine \foreignlanguage{english}{Message}
in eine Methode zu überführen, und damit ausführbar zu machen, heißt
,,bind``).

Damit hat man schon ein Werkzeug, das über die natürlichen Fähigkeiten
von Forth hinausgeht. \noun{Klaus Schleisiek} hat einmal einen Vortrag
über die verschiedenen Adressräume von Microcontrollern und DSPs gehalten,
und die Forth--übliche Lösung führt zu einer Explosion der Wörternamen
und unwartbaren Programmen --- weil man sich bei jeder Adresse merken
muss, ob die jetzt im Flash, im EEPROM, im internen RAM, im X-- oder
Y--RAM eines DSPs, im Code--Memory einer \foreignlanguage{english}{Harvard}--Architektur,
im externen RAM, im IO--Bereich, in einem über SPI oder I$^{2}$C
adressierten externen IO--Baustein oder wo auch immer ist. Führt man
hier ein bisschen OOP ein, kann man jeder Variablen die Methoden @
und ! zuordnen, und diese jeweils für die verschiedenen Speicherbereiche
unterschiedlich implementieren. Die so definierten Variablen ,,wissen,``
wie sie auf @ und ! zu reagieren haben, der Programmierer muss das
nicht mehr selbst machen. Die Variablen sind im Quelltext durch ihren
Namen referenziert, ihre Klasse ist also bekannt und die Methoden
können früh gebunden werden. Wartbarkeit ist wieder erreicht, durch
das Prinzip ,,\foreignlanguage{english}{information hiding,}`` denn
wo die Variable jetzt liegt, und wie sie angesprochen werden muss,
ist ihr Privat--Wissen, dem Programmierer, der sie verwendet, kann
das jetzt egal sein. Hier spricht man von \foreignlanguage{english}{,,interfaces}``
(das sind in diesem Beispiel @ und !) und ,,\foreignlanguage{english}{implementations}``
(das sind die jeweiligen Umsetzungen für unterschiedliche Adressräume).
Der Code dazu sieht ungefähr so aus (Syntax: Bernd\-OOF, ich nehme
an, dass die forthige Lösung für den Zugriff auf Flash und SPI schon
implementiert ist, und nur noch der OOP--Wrapper darum gelegt wird,
um das ganze wartbar zu machen). Zur Konflikt--Bereinigung zwischen
den Methoden @ und ! und den Forth--Wörtern @ und ! gibt es das Präfix
F, das explizit im Forth--Wörterbuch sucht. Man könnte auch dem Vorschlag
von \noun{Doug Hoffman} folgen, und allen Messages einen : hinzufügen.
Das ist aber ein Konzept aus einer anderen Sprache. In Forth sind
Messages auch einfach nur Forth--Wörter.
\begin{lyxcode}
object~class~memvar

~~~cell~var~addr

~~~method~@

~~~method~!

how:

~~~:~init~(~addr~-{}-~)~addr~F~!~;

~~~:~!~(~n~-{}-~)~~addr~F~@~F~!~;

~~~:~@~(~-{}-~n~)~~addr~F~@~F~@~;

class;
\end{lyxcode}
Ich verwende memvar im Folgenden auch gleich als Basisklasse, die
hier nicht abstrakt ist, sondern konkret --- mit der einfachst möglichen
Implementierung.
\begin{lyxcode}
memvar~class~flashvar

how:

~~~:~!~(~n~-{}-~)~~addr~F~@~flash!~;

class;
\end{lyxcode}
Das Flash beschreiben funktioniert anders, lesen kann man es aber
wie normalen Speicher.
\begin{lyxcode}
memvar~class~spivar

how:

~~~:~!~(~n~-{}-~)~~addr~F~@~spi!~;

~~~:~@~(~-{}-~n~)~~addr~F~@~spi@~;

class;
\end{lyxcode}
SPI liest und schreibt man über einen seriellen Datenbus. Jetzt brauchen
wir noch etwas Test--Code:
\begin{lyxcode}
here~0~,~memvar~:~a

\$20~~~~~~spivar~:~b

\$FFEA~~flashvar~:~c



\$1234~a~!

a~@~c~!

c~@~b~!

b~@~hex.~(~sollte~\$1234~geben~)
\end{lyxcode}
Die meisten mir bekannten Forth--OOP--Systeme implementieren das jetzt
als Early Binding. Das, was daraus entsteht, ist kein OOP, sondern
,,operator overloading,`` der gleiche Operator auf verschiedene
Datentypen angewandt wird unterschiedlich implementiert --- die Datentypen
sind ihrerseits aber statisch, also von vornherein bekannt.

Das ist natürlich noch nicht sonderlich flexibel --- normale Variablen
kann man einfach auf den Stack legen, und generische Funktionen können
einfach @ und ! darauf anwenden, um etwa +! zu implementieren:
\begin{lyxcode}
:~+!~(~n~addr~-{}-~)~~dup~>r~@~+~r>~!~;
\end{lyxcode}
Man kann nun natürlich einfach +! als Methode für jeden Speicherbereich
implementieren, das +! darf auch ruhig jedes Mal gleich aussehen,
aber wenn @ und ! früh gebunden werden, muss der Code jedes Mal neu
übersetzt werden --- für jede Klasse einmal. Einfacher wäre es, @
und ! würden spät gebunden, also erst zur Laufzeit (in obigem Beispiel
ist das so, weil Bernd\-OOF tatsächlich per Default spät bindet).
Diese Eigenschaft nennt man ,,Polymorphismus``, Unterklassen haben
unterschiedliche Gestalt, und das Senden der gleichen Message führt
zu verschiedenen Aktionen --- wobei dem verwendenden Programm nicht
bekannt sein muss, mit welcher Unterklasse es zu tun hat. Wir haben
es hier also mit dynamischem Typing zu tun --- der Datentyp (die Klasse)
des Objekts ist erst zur Laufzeit bekannt.

Das (recht klassische und einfache) Design--Pattern, das hier verwendet
wird, um das zu implementieren, ist das der ,,Indirektion.`` Man
kann in der Informatik, so heißt es, jedes Problem durch eine zusätzliche
Indirektion lösen --- also indem man einen Pointer benutzt, statt
den Wert selbst.

Die Indirektion, die hier nötig ist, ist die beim Aufruf der Methode.
Naheliegend ist es, einfach eine Instanz--Variable für jede Message
zu definieren, und dort das xt der Methode zu speichern --- wie bei
einem \foreignlanguage{english}{deferred word}. Man kann das so machen,
es verschwendet nur Speicher, denn die Methoden sind ja für alle Objekte
einer Klasse gleich.

Die Lösung dazu ist (wie in der Informatik üblich) eine Indirektion,
die als ,,vtable`` oder ,,\foreignlanguage{english}{virtual method
table}`` bezeichnet wird. Man gibt also jedem Objekt einer Klasse
einen Pointer mit, auf eine Datenstruktur, in der die Methoden einer
Klasse gemeinsam verwaltet werden. Üblicherweise ist das ein Array,
d.h. jede Methode ist über einen Index schnell und ziemlich direkt
zugreifbar, aber man kann da auch Hash--Tables oder Listen verwenden,
wenn etwa das Ziel eine Implementierung ist, bei der jedes Objekt
jede Message verstehen kann, und damit ein Array als vtable zu viel
Speicherplatz kosten würde. Abbildung \ref{fig:Ein-Objekt-der} zeigt,
wie das im Speicher aussieht.

\begin{figure}


\begin{centering}
\includegraphics[scale=0.4]{2011-04/vtable}
\par\end{centering}

\caption{\label{fig:Ein-Objekt-der}Ein Objekt der Klasse memvar und seine
vtable}


\end{figure}


Deshalb, um das nochmal deutlich zu machen: Eine vtable ist deshalb
getrennt vom Objekt abgelegt, um Speicherplatz zu sparen. Die entscheidende
Indirektion ist nicht der Pointer auf die vtable, sondern der Pointer
auf die Methode, die aus einem Forth--Wort, das im Kontext des Objekts
aufgerufen wird, eine polymorphe Message macht --- eine Art \foreignlanguage{english}{deferred
word}, nur eben nicht als Instanz--Variable, sondern für alle Instanzen
einer Klasse gemeinsam.

Viele objektorientierte Sprachen verstehen unter ,,\foreignlanguage{english}{information
hiding}``, dass der Zugriff auf im Objekt intern verwendete Funktionen
von außen nicht gestattet ist. Das widerspricht der Forth--Philosophy
,,\foreignlanguage{english}{don't bury your tools}``, und muss zumindest
für's Debugging abschaltbar sein. Meiner Meinung nach ist das auch
ein Missverständnis, denn wirklich gemeint ist, dass man zur Kommunikation
mit anderen Objekten ihre Interfaces, nicht ihre Implementierung verwenden
soll. Das sind aber alles Regeln, keine Gesetze; Regeln, deren Befolgung
meistens sinnvoll ist, und deren Verletzung begründet werden sollte.
In Forth ist die Durchsetzung solcher Regeln durch den Compiler nicht
üblich.


\section{Design Pattern: Komposition statt Vererbung}

Das Meta--Pattern schlechthin bei den Design--Pattern ist, statt Vererbung
die Komposition von Objekten zu verwenden. Vererbung ist sinnvoll,
um verschiedene Ausformungen einer Klasse zu bekommen; die Komposition
von Objekten ist aber flexibler, und verknüpft ganz unterschiedliche
Eigenschaften. Vererbung ist ein Kopiervorgang (ungeschlechtlich,
wie die Fortpflanzung von Bakterien), Komposition ist im Verhältnis
dazu wie Sex --- mit mehreren Teilnehmern, die ihre unterschiedliche
Herkunft einbringen.

Ich möchte das einmal am Beispiel eines Dialog--Fensters in MINOS erläutern,
was damit gemeint ist. Die beiden Relationen, um die es hier geht,
werden mit ,,is--a`` und ,,has--a`` bezeichnet. Ein Dialog--Fenster
in MINOS \textbf{ist} eine Komponente (das ist die Klasse, von der
es abgeleitet wird). Es \textbf{hat} mehrere Sachen: Zum einen ein
Display--Objekt, in dem es dargestellt wird (das ist üblicherweise
ein Fenster). Zum anderen hat es Widgets, in der Regel eine ganze
Menge, die ihrerseits in horizontalen und vertikalen Boxen angeordnet
sind. Auch für Widgets gelten derartige Beziehungen: Ein Widget ist
z.B. ein Button. Es hat eine (oder mehrere miteinander verkettete)
Aktion(en), die ausgeführt werden, wenn man darauf klickt. Und es
hat natürlich auch ein Display, in dem es dargestellt wird.

Die ,,is--a``--Beziehung wird durch Instantiierung und Vererbung
erworben, einmal instantiiert lässt sie sich nicht mehr verändern
(ein Button bleibt ein Button). Die ,,has--a``--Beziehung durch
Zuweisungen, etwa durch Einhängen in die Liste einer Box. Letzteres
erfolgt zur Laufzeit, und kann auch während der Laufzeit geändert
werden (es können neue Elemente in eine Box eingehängt werden, oder
Elemente daraus gelöscht werden). Das ist sehr dynamisch und sehr
flexibel. Das dazu verwendete Konstrukt ist, wie nicht anders zu erwarten,
eine Indirektion, ein Pointer auf ein Objekt.

Die meisten dieser Design--Pattern funktionieren nur mit late binding,
manche brauchen sogar Mehrfachvererbung. Ein umfassendes OOP--System
sollte es ermöglichen, alle Pattern auszudrücken; wenn man nur spezielle
Anwendungsfälle für einige der Pattern hat, reicht manchmal eine reduzierte
Version. Ich liste diese Pattern in der Reihenfolge der Gang--of--Four
auf, und erkläre kurz, was damit gemeint ist, sowie welche Fähigkeiten
des OOP--Systems nötig sind, um diese Pattern zu implementieren.

Da Forth eine sehr dynamische Sprache ist, und die Design--Pattern
sich auf C++ und Java beziehen, fehlen Design--Pattern, die man in
diesen Sprachen einfach nicht machen kann. Man muss also auch dieses
hier als Minimal--Konsens verstehen, und durchaus in Erwägung ziehen,
dass man das auch anders (und besser) machen kann.


\subsection{Creational Patterns}

Diese Pattern haben das Erzeugen von Objekten zum Thema
\begin{description}
\item [{Abstract~Factory}] Erzeugt verwandte oder voneinander abhängige
Objekte, ohne die konkrete Klasse zu spezifizieren.


Beispiel: Wir verwenden obige Klassen, um Variablen in verschiedenen
Speicherbereichen zu verwalten, wollen aber den Ort unabhängig von
den Variablen selbst spezifizieren. Dazu bauen wir uns einen globalen
Status, der % entsprechend des aktuell verwendeten Speicherbereichs
dem aktuell verwendeten Speicherbereich entsprechend
gesetzt ist, und erzeugen in der Abstract Factory immer die passenden
Objekte. Wenn unser ADC jetzt vom SPI--Bereich in den I$^{2}$C--Bereich
verschoben wird (z.B. weil er beide Interfaces anbietet, der eine
Controller aber SPI und der andere I$^{2}$C verwendet), dann ändern
wir nur den Bereich, und lassen den Rest des Quellcodes unverändert.


Dabei kann es verschiedene Klassen geben, die ausgewählt werden, etwa
Klassen für Bytes, für 16-- und 32--Bit--Wörter, die alle gemeinsam
abhängig vom gerade gewählten Speicherbereich erzeugt werden können.


Das OOP--System muss Objekt--Pointer beherrschen und echten Polymorphismus,
weil der Aufrufer der Abstract Factory nicht weiß, was für ein Objekt
er bekommt. Es ist hilfreich zur Implementierung, wenn Klassen ebenfalls
herumgereicht und als Pointer abgelegt werden können (etwa, um eine
Klassenmatrix anzulegen). Im Beispiel oben werden die Objekte während
der Compilation erzeugt und in anderen Teilen des Programms direkt
als benannte Variable verwendet (und da das Binding nach der Erzeugung
der Objekte geschieht, auch ggf. mit Early Binding), das ist etwas,
was in C++ und Java so gar nicht geht.

\item [{Builder}] Erzeugt komplexe Objekte, etwa zum Konvertieren von einem
Dateiformat in ein anderes.


Beispiel: Wir wollen ein RTF--Dokument in ASCII oder \LaTeX{} konvertieren.
Dazu spezifizieren wir das Ziel, und der Builder erzeugt entweder
ein ASCII-- oder ein \LaTeX{}--Dokument--Objekt. Beide Objekte nehmen
Text und Formatierungsanweisungen des RTF--Readers entgegen, der ASCII--Builder
baut aber nur die Strings in die Ausgabe ein, während der \LaTeX{}--Builder
auch die Formatierungsanweisungen übersetzt.


Auch hier muss das OOP--System Objekt--Pointer und Polymorphismus
beherrschen.

\item [{Factory~Method}] Erzeugt Objekte, wobei die Klasse durch einen
Parameter spezifiziert ist, oder in Unterklassen variiert wird, ähnlich
der Abstract Factory, nur dass hier eine Methode verwendet wird, um
ein Objekt zu erzeugen. Die Anforderungen an das OOP--System sind
die gleichen wie bei der Abstract Factory
\item [{Prototype}] Hier spezifiziert man zunächst eine Instanz, den
  Prototypen (mit Variablen und Methoden), und erzeugt dann weitere
  Instanzen als Kopien davon.

Die wesentliche Forderung an das OOP--System ist, dass es den clone--Operator
implementieren kann, und dass Objekte während der Laufzeit neue Instanz--Variablen
und Methoden bekommen können --- dann ist das Prototyp--Pattern direkt
im System implementiert.

\item [{Singleton}] Eine Klasse, die nur genau einmal instantiiert werden
kann; dieses eine Objekt muss global verfügbar sein. Die Instantiierung
erfolgt beim ersten Zugriff, nicht beim Programmstart.


Die Forderung an das OOP--System hier ist, globale Variablen innerhalb
einer Klasse zu ermöglichen, und Methoden, die schon vor der Instantiierung
aufgerufen werden können --- diese Methoden können nicht late binding
sein.

\end{description}

\subsection{Structural Patterns}
\begin{description}
\item [{Adapter}] Ein Adapter konvertiert die Aktionen eines Interfaces
in ein anderes, um verschiedene bereits existierende Programme aneinander
anzupassen.


Beispiel: Eine Grafik--Ausgabe mit einem kartesischen Koordinatensystem
soll mit einem Adapter in eine Turtle--Grafik umgesetzt werden, weil
ein anderes existierendes Objekt eine Turtle--Grafik erwartet. Das
Adapter--Objekt wird also die Position und Richtung der Turtle als
Zustandsvariablen enthalten, und aus forward/backward eine entsprechende
lineto--Message berechnen.


Ein Adapter kann entweder durch Mehrfachvererbung (Class Adapter)
oder durch Komposition (Object Adapter) erzeugt werden.

\item [{Bridge}] So ähnlich wie ein Adapter, aber von vornherein im Entwurf
so vorgesehen. 


Wenn die Turtle--Grafik im obigen Beispiel von vornherein Design--Ziel
ist (wir wollen das als stabiles Interface für den User zur Verfügung
stellen), und die Grafik--Ausgabe je nach Ausgabe--Device das mehr
oder weniger direkt unterstützt (X Window System schlecht, OpenGL
mäßig, PostScript gut), dann sind die Objekte, die das konvertieren,
Bridges, nicht Adapter.

\item [{Composite}] Erlaubt es, Objekte zusammenzusetzen, und diese zusammengesetzten
Objekte ihrerseits genauso wie einzelne Objekte zu behandeln.


Beispiel MINOS: Hier gibt es Widgets und Boxes, und natürlich sind
Boxes ihrerseits wieder Widgets, die eben mehrere andere Widgets enthalten.


Das erfordert Objekt--Pointer und Late Binding.

\item [{Decorator}] Fügt zusätzliche Verantwortlichkeit dynamisch zu einem
Objekt hinzu. 


Beispiel MINOS: Die Aktionen, die ein Widget hat, können etwa mit
einem Tooltip--Objekt dekoriert werden. Die Aktion selbst ist unverändert
(ein Klick produziert das Gleiche wie ohne Tooltip), aber wenn der
Benutzer die Maus über dem Widget stehen lässt, wird ein Tooltip angezeigt.


Auch hier ist man mit Objekt--Pointern und Late Binding dabei.

\item [{Facade}] Stellt ein ,,einfaches`` Interface (in einer Klasse)
zur Verfügung, die in Wahrheit über eine ganze Kollektion verschiedener
Objekte implementiert wird.


Beispiel MINOS: Ein Slider besteht aus Pfeilen nach oben und unten,
einem abgesenkten Bereich und einem Slider darin, der den sichtbaren
Ausschnitt des Dokuments repräsentiert. Nach außen stellt sich der
Slider als ein Objekt dar, das die Position und den sichtbaren Ausschnitt
des Dokuments erfasst und verändern kann.


Je nach Anwendungsfall kann die Facade auch mit Objekt--Instanzvariablen
und Early Binding oder mit Objekt--Pointern und Late Binding implementiert
werden.

\item [{Flyweight}] Verwendet Objekte gemeinsam, um eine große Zahl von
Objekten effizient zu verwalten.


Beispiel: Die vtable eines Objektes kann man ja auch als Objekt auffassen.
Wie oben beschrieben, ist es sinnvoll, alle Objekte in einer Klasse
auf dieselbe vtable zeigen zu lassen, statt die vtable für jedes Objekt
zu duplizieren. In einem prototyp--basierten OOP ist es aber möglich,
einzelne Objekte später zu ändern, und neue Methoden hinzuzufügen
--- dann, aber erst dann, muss die vtable kopiert werden. Die Gang
of Four gibt als Beispiel eine Textverarbeitung an, die jeden Buchstaben
als Objekt (mit Bounding Box und grafischer Darstellung) speichert.
Jeden Buchstaben für sich natürlich nur einmal, um Speicher zu sparen.


Zwingend notwendig: Objekt--Pointer.

\item [{Proxy}] Ein Platzhalter für ein Objekt, um den Zugang zu kontrollieren.


Proxies werden auf vielerlei Weise eingesetzt; das Beispiel, das Andrew
Haley erwähnte, ist, um das Erzeugen des Objekts zu verzögern. Eine
Textverarbeitung kann einen Proxy nehmen, um das Laden und Darstellen
eines Bildes zu verzögern --- solange der Benutzer die Seite mit dem
Bild nicht anzeigt, existiert nur der Proxy, der die Größe des Bildes
dem Umbruchalgorithmus übergibt. Erst, wenn die draw--Methode des
Proxies aufgerufen wird, wird das eingebundene Bild komplett geladen
und dargestellt (das dauert und kostet Speicherplatz, will man längere
Dokumente bearbeiten, ist es sinnvoll, das nur bei Bedarf zu erledigen
--- der Speicher nicht mehr sichtbarer Bilder kann dann auch wieder
freigegeben werden). Auch die im Flyweight beschriebenen Buchstaben--Objekte
werden ein Proxy--Objekt benötigen, das z.B. die Position speichert.


Ein Proxy kann auch Zugangsbeschränkungen implementieren, etwa verhindern,
dass eine Datenbank manipuliert wird, wenn sich der User nicht eingeloggt
hat. Der Proxy implementiert in diesem Fall den Login--Vorgang, und
reicht schreibende Zugriffe erst nach einem erfolgreichen Login auf
das Datenbankobjekt durch. Ein Proxy kann aber auch verwendet werden,
um Objekte über's Netz anzusprechen.


Objekt--Pointer sind hier zwingend erforderlich; je nach
Anwendungsfall kann von vornherein bekannt sein, welches Objekt der
Proxy ersetzt (Early Binding möglich), oder auch nicht. Für den
Anwendungsfall, mit einem Proxy Nachrichten über's Netz zu schicken,
ist es sinnvoll, wenn das System Objekte serialisieren kann (also in
einer Form abspeichern, die man anderswo wieder laden kann --- in
Forth wäre das Sourcecode).

\end{description}

\subsection{Behavioral Patterns}
\begin{description}
\item [{Chain~of~Responsibility}] Mehrere Objekte in einer Kette bekommen
die gleiche Eingabe serviert, bis eines darauf reagiert.


Beispiel MINOS: Das Text--Eingabefeld muss auf Cursor--Tasten und
ähnliches reagieren. Jeder derartigen Taste ist ein Objekt zugeordnet,
das entsprechend reagiert.


Beispiel Recognizer: Die Recognizer, die \noun{Matthias Trute} in
amForth eingebaut hat, können als Chain of Responsibility aufgefasst
werden --- jeder Recognizer sieht sich das Forth--Wort an, und reagiert
entsprechend --- wenn es im Wörterbuch ist, wird es ausgeführt oder
compiliert, wenn es eine Zahl ist, umgewandelt, und auf den Stack
gelegt bzw. als Literal compiliert.


Dieses Pattern benötigt Object--Pointer und Late Binding, es kann
auch sinnvoll sein, deferred words als Instanz--Variablen zu ermöglichen.

\item [{Command}] Macht aus einem Kommando ein Objekt. Die Methode, die
ein command--Objekt zur Verfügung stellt, ist execute, es kann also
ausgeführt werden. Was es dabei tut, ist seine Sache. Es kann auch
mehrere Varianten von execute geben.


Beispiel MINOS: Die Aktionen, die ein Widget hat, rufen ganz spezifischen
Code auf (im Kontext eines anderen Objekts), haben aber ein gemeinsames
Interface. Kommandos sind die OO--Version von Callbacks.


Beispiel Forth: Wörter sind Kommandos; folgt man der Idee des ,,smart
compile,``, dann ist ein Wort auch tatsächlich ein richtig komplexes
Objekt, das ausgeführt, interpretiert, compiliert und mit postpone
später compiliert werden kann. Das geht über die einfache Struktur
eines Command--Objekts schon deutlich hinaus.


Objekt--Pointer und Late Binding sind zwingend erforderlich, deferred
words hilfreich. Auch hilfreich ist es, ein Stück Code im Kontext
eines Objekt--Pointers auszuführen, also dort mehrere Methoden aufzurufen,
ohne jedesmal zwischen dem Aufrufer und dem aufgerufenen Objekt umzuschalten
(Multi--Message).

\item [{Interpreter}] Erlaubt es, eine (einfache) Sprache als abstrakten
Syntax--Baum zu implementieren. Dieses Pattern ist für Forth--Nutzer
wohl eher uninteressant, da wir einfache Sprachen direkt in Forth
implementieren, und komplexere Sprachen einen Parser--Generator benötigen,
der von dem Pattern nicht umfasst wird.
\item [{Iterator}] Ein Iterator durchläuft zusammengesetzte Objekte sequenziell,
ohne die innere Struktur des Objekts offenzulegen (also unabhängig
davon, ob es ein Array oder eine Liste ist).


Der Iterator wandelt eine Klasse ab, also ist entweder Mehrfachvererbung
oder die Zuordnung eines bereits definierten Interfaces zur Klasse
hilfreich. Late Binding ist ebenso zwingend erforderlich.

\item [{Mediator}] Ein Mediator ist ein Objekt, das die Kommunikation zwischen
verschiedenen Objekten zentral behandelt, damit die einzelnen Objekte
nichts voneinander wissen müssen.


Beispiel MINOS: Das Komponenten--Objekt, das Dialoge implementiert,
ist auch ein Mediator zwischen den einzelnen Objekten im Dialog. Die
Kommandos werden alle an den Mediator gesendet, der weiß, wie die
verschiedenen Objekte miteinander interagieren.


Objekt--Pointer sind zwingend erforderlich, je nach notwendiger Flexibilität
des Mediators kann aber Early Binding ausreichen.

\item [{Memento}] Erfasst und speichert den Zustand eines Objekts, um es
später zu restaurieren.


Beispiel: Um die Undo--Operation in einem Editor zu implementieren,
speichert das Memento bei jedem Backspace das gelöschte Zeichen und
dessen Position im Text. Führt man später Undo aus, werden diese Zeichen
wieder an der richtigen Stelle eingefügt.


Objekt--Pointer und Late Binding sind erforderlich.

\item [{Observer}] Wenn der Zustand eines Objekts sich ändert, werden alle
abhängigen Objekte benachrichtigt.


Beispiel Facebook: Wenn man einen Eintrag auf seine Pinwand schreibt,
werden alle Freunde benachrichtigt, und bekommen den Eintrag in ihren
Neuigkeiten zu sehen.


Objekt--Pointer, Late Binding und zumindest Interfaces (ggf. auch
Mehrfachvererbung) sind nötig.

\item [{State}] Dieses Pattern beschreibt eine State--Maschine, wobei für
jeden Zustand eine andere Klasse verwendet wird --- die Funktionen
zum Ändern des Zustands sind die Methoden der Zustands--Objekte, sie
ändern sich abhängig vom Zustand.


Das State--Pattern kann direkt in einem OOP--System implementiert
werden, wenn es möglich ist, die Klasse des Objekts zur Laufzeit zu
ändern (durch Ändern des vtable--Pointers).

\item [{Strategy}] Definiere eine Familie von Algorithmen, die austauschbar
sind.


Beispiel: Ein Roboter sucht sich einen Weg, und verwendet dabei je
nach Situation unterschiedliche Algorithmen. Auf freiem Feld kann
er etwa den kürzesten Weg zum Ziel berechnen, in einem Labyrinth muss
er das Terrain erkunden und eine Karte erzeugen.


Objekt--Pointer und Late Binding sind erforderlich.

\item [{Template~Method}] Definiert das Skelett eines Algorithmus, der
dann in Unterklassen verfeinert wird.


Beispiel Forth: Compiler und Interpreter parsen jeweils ein Wort aus
dem Eingabestrom, bearbeiten das dann aber unterschiedlich. Statt
STATE @ IF .. ELSE .. THEN zu schreiben, definiert man einen Hook,
der dann in den Unterklassen compiler und interpreter implementiert
wird.


Late Binding ist erforderlich.

\item [{Visitor}] Eine Operation auf alle Elemente eines Composite.


Beispiel MINOS: Bei der Formatierung der Objekte wird jedes Objekt
in einer Box nach minimaler und maximaler Ausdehnung gefragt, und
daraus berechnet, welche Position und Größe es in der Box haben wird.


Objekt--Pointer und Late Binding sind erforderlich, die Möglichkeit,
mehrere Methoden im Kontext eines Objekt--Pointers hintereinander
aufzurufen, hilfreich. Es ist auch hilfreich, wenn man Teile eines
Wortes innerhalb einer impliziten Schleife ausführen kann --- in MINOS
verwende ich dafür Return--Stack--Tricks. Ebenfalls nützlich ist eine
Tail--Call--Optimization, um Returnstack--Platz zu sparen.

\end{description}

\section{Was bleibt zu tun}

Ich habe mein OOP (,,Bernd\-OOF``) schon ein paar Jahre vor der
Veröffentlichung des Design--Pattern--Buchs geschrieben, und zum Teil
erst hinterher so erweitert, dass die meisten Design--Pattern implementierbar
sind. Manchmal nicht ganz so elegant, wie man sich das wünscht, manchmal
auf eine sehr forthige Art, die zumindest den Compiler von VFX Forth
überfordert (das Visitor--Pattern wird in MINOS durch eine implizite
Schleife implementiert, die am Returnstack herummanipuliert). Die
Implementierung eines OOP--Systems ist leider immer ,,Guru Code,``
wie Stephen Pelc es ausdrückt; es ist nichts offensichtlich, es muss
alles umfangreich dokumentiert werden; da ein neues Programmier--Paradigma
implementiert wird, kann man sich nicht auf gemeinsame Kenntnisse
verlassen. Das ist bei praktisch keinem existierenden OOP--System
wirklich der Fall, jedenfalls nicht in dem nötigen Ausmaß. Auch wenn
Bernd\-OOF meiner Ansicht nach verwendbar ist, und die anderen OOP--Systeme
für Forth zu viele Mängel haben, ist es keine Lösung für das Problem,
das wir haben. Es ist auch nicht wirklich portabel, die Implementierung
einer performanten Lösung ist nicht trivial, und ein signifikanter
Teil des VFX--Compilers (der Inliner) musste komplett neu geschrieben
werden, um das richtig zu compilieren (das war aber eine Aktion, die
ohnehin notwendig war).

Ich finde den Common--Lisp--Ansatz des Metaobjekt--Protokolls sehr
interessant, und werde versuchen, etwas Ähnliches in Forth zu implementieren.
Die Idee dahinter ist, das OOP--System selbst unter Verwendung objektorientierter
Programmierung zu implementieren, und so die notwendige Flexibilität
zu erreichen. Als Implementierungsbasis, also zum Bootstrappen des
OOPs, werde ich mein Mini--OOP verwenden, die 12 Zeilen, die Vtables
und Instanz--Variablen implementieren, mehr aber nicht. Ziel ist,
dass man damit dann Syntax und Semantik bestehender OOP--Systeme,
also etwa von SWOOP, FMS, Bernd\-OOF und anderen implementieren kann,
und diese Systeme auch jederzeit erweitern kann (etwa um Mehrfachvererbung),
ohne wie bisher intime Kenntnis über die jeweiligen Systeme zu haben
--- nur die Kenntnis des Metaobjekt--Protokolls ist natürlich zwingend
nötig.

Es soll im so entstehenden System möglich sein, Klassen aus verschiedenen
OOP--Systemen zu verknüpfen, und gemeinsam zu verwenden. Dabei muss
es möglich sein, dass die Implementierung deutlich voneinander abweicht
--- Bernd\-OOF z.B. hat eine C++/Java--artige Klassenhierarchie,
in der jedes Objekt nur die Messages versteht, die es entweder geerbt
oder selbst definiert hat. Andere Messages werden schon zur Compile--Zeit
abgewiesen. FMS dagegen implementiert das Smalltalk--Model, bei der
jedes Objekt prinzipiell jede Message versteht, zumindest über die
,,kannitverstan``--Methode, die aber erst zur Laufzeit ausgeführt
wird, und eine Fehlermeldung produziert. Die vtables in Bernd\-OOF
implementiert man am besten als Arrays (da sie immer dicht besetzt
sind, die kompakteste Darstellung im Speicher), die vtables von FMS
eher als Listen oder Hashes, da sie dünn besetzt sind (die meisten
Klassen implementieren nur wenige Messages, und verstehen die vielen
anderen Messages nicht).

Es soll auch möglich sein, degenerierte Klassen und Objekte zu erzeugen,
die eben nur Early Binding können und keinen vtable--Pointer haben,
weil viele Forth--Programmierer offensichtlich damit glücklich sind.
Die einzelnen Fähigkeiten eines kompletten OOP--Systems sollten getrennt
voneinander implementierbar sein, und als Erweiterungen betrachtet
werden können. Wenn ich also z.B. Multiple Inheritance brauche (Bernd\-OOF
kann das derzeit nicht), dann lade ich es einfach dazu.

Die notwendigen Primitives, also der Zugriff auf Instanz--Variablen
über einen this/self--Pointer, die performante Ausführung von bind(message)
über vtables (Arrays und Listen/Hashes), und die Erweiterbarkeit des
äußeren Interpreters um Namensräume für Klassen müssen von der eigentlichen
Syntax und Semantik des OOP--Systems getrennt werden können, damit
man nur diesen Low--Level--Teil portieren und für jedes Forth--System
extra warten muss.

\begin{thebibliography}{1}
\bibitem{gof}\noun{Erich Gamma, Richard Helm, Ralph Johnson, John
Vlissides: }\emph{Design Patterns: Elements of Reusable Object--Oriented
Software}

\bibitem{ca}\noun{Christopher Alexander, Sara Ishikawa, Murray Silverstein,
Max Jacobson, Ingrid Fiksdahl--King, Shlomo Angel: }\emph{A Pattern
Language}

\bibitem{tf}\noun{Leo Brodie,}\emph{ Thinking Forth}

\bibitem{mop}\noun{Gregor Kiczales, Jim des Rivières, Daniel G. Bobrow,
}\emph{The Art of the Metaobject Protocol}
\end{thebibliography}

\end{multicols}
\end{document}
