docs/DesignPatterns

annotate detailed-observer.tex @ 33:97b57d24fd7b

added sample code; modified summary
author meillo@marmaro.de
date Fri, 10 Aug 2007 22:15:51 +0200
parents 3d6e01222e28
children b2cefbd90180
rev   line source
meillo@11 1 % @file
meillo@28 2 % @brief Referat DesignPatterns `Observer'
meillo@11 3 % @author markus schnalke <meillo@marmaro.de>
meillo@11 4 % @since 2007-05-30
meillo@11 5
meillo@11 6
meillo@28 7 \documentclass[a4paper]{scrartcl}
meillo@11 8
meillo@28 9 \usepackage[utf8]{inputenc}
meillo@11 10 \usepackage{ngerman}
meillo@11 11 \usepackage{graphicx}
meillo@33 12 \usepackage{listings}
meillo@11 13 \usepackage[automark]{scrpage2}
meillo@11 14
meillo@28 15 \setkomafont{sectioning}{\normalfont\normalcolor\bfseries}
meillo@28 16 \setlength{\parindent}{0em}
meillo@28 17 \setlength{\parskip}{1.0ex plus 1.0ex minus 0.5ex}
meillo@28 18 \pagestyle{scrheadings}
meillo@31 19 \setcounter{tocdepth}{3}
meillo@11 20
meillo@11 21 \begin{document}
meillo@11 22
meillo@11 23
meillo@11 24
meillo@11 25
meillo@11 26
meillo@28 27 %%%% Titlepage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
meillo@28 28 \begin{titlepage}
meillo@28 29 \title{Observer-Pattern}
meillo@28 30 \author{Markus Schnalke}
meillo@28 31 \date{2007-07-04}
meillo@11 32
meillo@11 33
meillo@28 34 \thispagestyle{empty}
meillo@11 35
meillo@11 36
meillo@28 37 \begin{flushright}
meillo@11 38
meillo@28 39 \rule[8cm]{0cm}{0cm}
meillo@28 40 {\Huge Design Pattern\\ \textbf{Observer}}
meillo@11 41
meillo@28 42 \rule[2cm]{0cm}{0cm}
meillo@28 43 \textsc{Markus Schnalke\\MatNr: 039131}
meillo@11 44
meillo@28 45 \end{flushright}
meillo@11 46
meillo@11 47
meillo@11 48
meillo@28 49 \rule[7cm]{0cm}{0cm}
meillo@11 50
meillo@28 51 \textit{Dies ist meine Ausarbeitung zum Design Pattern ``Observer'' im Rahmen der Vorlesung Softwaretechnik im Studiengang Wirtschaftsinformatik an der Hochschule Ulm.}
meillo@11 52
meillo@28 53 {\tiny Dieses Dokument darf gerne zitiert, kopiert und weitergegeben werden. Ich bitte nur darum meinen Namen und einen Verweis auf meine Website (http://marmaro.de) zu erwähnen --- danke! }
meillo@11 54
meillo@11 55
meillo@28 56 \end{titlepage}
meillo@11 57
meillo@11 58
meillo@11 59
meillo@28 60
meillo@28 61 \tableofcontents
meillo@28 62
meillo@28 63
meillo@28 64
meillo@28 65
meillo@28 66
meillo@28 67
meillo@28 68
meillo@28 69
meillo@28 70
meillo@28 71
meillo@28 72
meillo@28 73
meillo@28 74
meillo@28 75
meillo@28 76 %%%% Einleitung %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
meillo@28 77 \newpage
meillo@28 78 \section{Einleitung}
meillo@28 79
meillo@28 80 Ich möchte im Folgenden einen Ansatz zum Verstehen von Design Patterns aufzeigen. Dazu nehme ich das Design Pattern ``Observer'', das ich Stück für Stück aus einer Situation der realen Welt herleiten werde. Es geht mir dabei nicht primär darum euch dieses Pattern zu erklären, vielmehr soll das Erfassen des Zusammenhangs zwischen Realität und Design Patterns gefördert werden.
meillo@28 81
meillo@28 82 Mein Ziel ist es die \textit{Natürlichkeit} von Design Patterns darzustellen --- weil sie dem Vorgehen in der Realität entsprechen!
meillo@28 83
meillo@28 84
meillo@28 85
meillo@28 86
meillo@28 87 \section{Meine Vorgehensweise}
meillo@28 88
meillo@28 89 \begin{quote}
meillo@28 90 Design Pattern sind ``Best Practices'' (= Erfolgsrezepte), meist \textbf{nach Vorbildern in der Realität}.
meillo@28 91 \end{quote}
meillo@28 92
meillo@28 93 Aus diesem Grund möchte ich nun anhand eines Beispiels aus dem täglichen Leben zeigen, dass das Design Pattern \textbf{Observer} ein absolut natürliches Vorgehen ist, das bei ähnlichen Situationen in Programmen deshalb ebenso verwendet werden sollte. Dass ich hier gerade das Pattern \textbf{Observer} verwende, hat keinen besonderen Grund; es kann wohl (fast) jedes Pattern auf diese Weise verständlich und logisch gemacht werden.
meillo@28 94
meillo@28 95
meillo@28 96
meillo@28 97
meillo@28 98
meillo@28 99
meillo@28 100
meillo@28 101
meillo@28 102
meillo@28 103
meillo@28 104
meillo@28 105
meillo@28 106
meillo@28 107
meillo@28 108
meillo@28 109 \newpage
meillo@28 110 \section{Erarbeitung des Patterns}
meillo@28 111
meillo@28 112 \subsection{Ausgangssituation}
meillo@28 113 Meine Ausgangssituation von der ich mich zu einer möglichst optimalen Lösung vorarbeiten möchte ist Folgende:
meillo@28 114
meillo@11 115 \begin{itemize}
meillo@28 116 \item Es gibt Personen die Etwas verkaufen möchten
meillo@28 117 \item Es gibt Personen die Etwas kaufen möchten
meillo@11 118 \item Sie wollen/sollen sich nicht kennen
meillo@11 119 \end{itemize}
meillo@11 120
meillo@28 121 Gesucht ist natürlich ein möglichst effektives Vorgehen. Eben das ist der Grund, weshalb wir Patterns verwenden möchten: Wir suchen eine effektive Standardlösung für regelmäßig auftretende Problemstellungen.
meillo@28 122
meillo@11 123
meillo@11 124
meillo@11 125
meillo@28 126 \subsection{Mögliche Ansätze}
meillo@28 127
meillo@28 128 Um systematisch vorzugehen, überlegen wir uns zunächst, welche primitiven Lösungen für unser Problem in Frage kommen. Dies wären zum Beispiel:
meillo@11 129 \begin{itemize}
meillo@11 130 \item Personen direkt ansprechen
meillo@11 131 \item Laut in die Menge rufen
meillo@11 132 \item Den Freunden erzählen, die es dann weitererzählen
meillo@11 133 \end{itemize}
meillo@11 134
meillo@28 135 Vermutlich wäre der Eine oder Andere (unbewusst) gleich höher eingestiegen, dennoch zeigen auch (oder gerade) diese simplen Vorgehensweisen Probleme auf, die sonst kaum explizit wahrgenommen werden.
meillo@28 136
meillo@28 137 Dies sind unter anderem:
meillo@28 138
meillo@11 139 \begin{itemize}
meillo@11 140 \item Man weiß nicht wer Interesse hat
meillo@11 141 \item nicht mal wieviele
meillo@11 142 \item Manche Interessenten sind vielleicht nur zu bestimmten Zeiten da
meillo@28 143 \item (... oder sie sind taub)
meillo@11 144 \end{itemize}
meillo@11 145
meillo@28 146
meillo@11 147
meillo@11 148
meillo@11 149
meillo@11 150 \subsection{Erarbeitung einer Lösung}
meillo@11 151
meillo@29 152 Im Folgenden möchte ich nun eine Lösung Schritt für Schritt erarbeiten und verbessern, bis sie das unsere Situation auf eine gute Weise löst.
meillo@29 153
meillo@29 154 Meine Lösung, die ich nun präsentieren möchte, ist eine Pinnwand. Pinnwände werden in der Realität normalerweise verwendet um derartige Problem zu lösen --- kein Wunder, wie wir gleich sehen werden. Die Pinnwand bietet von sich aus schon eine gute Lösung für unsere Problemsituation.
meillo@29 155
meillo@29 156
meillo@28 157 \subsubsection{Eine (gute) Lösung: Pinnwand}
meillo@11 158
meillo@29 159 Die Funktionen die eine Pinnwand anbietet sind:
meillo@28 160
meillo@11 161 \begin{itemize}
meillo@11 162 \item Man kann Zettel anpinnen
meillo@11 163 \item Hingehen und nach neuen Zetteln schauen
meillo@11 164 \item Zettel lesen
meillo@11 165 \item Zettel abnehmen
meillo@11 166 \end{itemize}
meillo@11 167
meillo@29 168 Nun sind zwar einige unserer Probleme (wie z.B. dass sich die Personen nicht kennen müssen) gelöst, doch es gibt auch welche die weiterhin bestehen. Dies sind vor allem:
meillo@11 169
meillo@11 170 \begin{itemize}
meillo@11 171 \item Man muss hingehen, nur um festzustellen, dass nichts Neues dabei ist
meillo@11 172 \item Man kann wichtige Zettel verpassen
meillo@11 173 \item Zettel sollten nicht weggenommen werden können
meillo@11 174 \end{itemize}
meillo@11 175
meillo@29 176 Diese Unzulänglichkeiten der jetzigen Lösung gilt es nun Schritt für Schritt zu eliminieren.
meillo@11 177
meillo@11 178
meillo@28 179 \subsubsection{Verbesserung: Pinnwand-Sekretärin}
meillo@11 180
meillo@29 181 Mit diesem Semester wurden bei uns Studiengebühren eingeführt. Die häufigen Diskussionen deswegen waren es wohl, die mich auf die Idee gebracht haben, das Geld doch sinnvoll(er) zu investieren. Und so erweitern wir unsere Pinnwand um eine Sekretärin die die Pinnwand verwaltet \dots natürlich mit Studiengebühren finanziert ;-)
meillo@29 182
meillo@29 183 Nachfolgend möchten wir die Sekretärin und die Pinnwand als Einheit betrachten. Die neuen Features dieser Pinnwand-Sekretärin-Einheit sind folgende:
meillo@29 184
meillo@11 185 \begin{itemize}
meillo@11 186 \item Man kann bei ihr einen Zettel in Auftrag geben (auch telefonisch)
meillo@11 187 \item (Sie schreibt mit lesbarer Schrift)
meillo@11 188 \item Sie verhindert, dass Zettel abgenommen werden
meillo@11 189 \end{itemize}
meillo@11 190
meillo@29 191 \dots und wir sind der optimalen Lösung unserer Problemsituation wieder einen Schritt näher. Jedoch nur einen Schritt, denn nicht alle Probleme sind gelöst.
meillo@29 192 Bestehen bleibt, dass man immer noch oft unnötig zur Pinnwand läuft.
meillo@28 193
meillo@11 194
meillo@11 195
meillo@11 196
meillo@28 197 \subsubsection{2. Verbesserung: Pinnwand-Sekretärin mit Benachrichtigung}
meillo@11 198
meillo@29 199 Die Studiengebühren sollen uns an dieser Stelle noch nicht ausgedient haben ---immerhin sind es 500 Euro--- und so ist noch genug übrig um userer Sekretärin verlängerte Arbeitszeiten finanzieren zu können. In dieser zusätzlichen Zeit kann sie nun natürlich weitere Aufgaben übernehmen. Dies sind:
meillo@29 200
meillo@11 201 \begin{itemize}
meillo@11 202 \item Man kann sich bei der Sekretärin nun als ``Interessierter'' registrieren
meillo@11 203 \item Die Sekretärin trägt die Telefonnummer in eine Liste ein
meillo@28 204 \item Zukünftig ruft sie alle Personen der Liste an, wenn sie einen neuen Zettel anpinnt
meillo@11 205 \end{itemize}
meillo@28 206
meillo@11 207
meillo@11 208
meillo@11 209
meillo@28 210 \subsection{Zusammenfassung des Beispiels}
meillo@11 211
meillo@30 212 Wir haben nun eine Lösung die die meisten Probleme unserer Situation löst. Ich möchte hier die Funktionsweise nochmals aufzählen:
meillo@30 213
meillo@30 214 \begin{itemize}
meillo@30 215 \item Man kann neue Zettel anpinnen lassen
meillo@30 216 \item Man kann sich als Interessierter anmelden (und auch abmelden)
meillo@30 217 \item Interessierte werden bei Änderungen der Pinnwand benachrichtigt
meillo@30 218 \item Sie können dann zur Pinnwand gehen und sie sich anschauen
meillo@30 219 \end{itemize}
meillo@11 220
meillo@28 221
meillo@30 222 Sind jetzt alle Anforderungen abgedeckt? Ist die geschaffene Struktur zufriedenstellend? Welche Wünsche sind noch offen? Was fehlt?
meillo@11 223
meillo@30 224 Es gibt natürlich weitere Anforderungen/Wünsche die über das jetzige Modell hinausgehen. Auf einige der verbreitendsten Erweiterungen des Observer-Modells werde ich weiter unten noch eingehen.
meillo@30 225
meillo@11 226
meillo@11 227
meillo@11 228
meillo@11 229
meillo@11 230
meillo@11 231
meillo@11 232
meillo@11 233
meillo@11 234
meillo@11 235
meillo@28 236
meillo@28 237
meillo@28 238
meillo@28 239
meillo@28 240
meillo@28 241
meillo@28 242
meillo@28 243
meillo@28 244
meillo@28 245
meillo@28 246
meillo@28 247
meillo@28 248 \newpage
meillo@28 249 \section{Das Pattern}
meillo@28 250
meillo@30 251 Nun haben wir uns eine Lösung für unser Problem erarbeitet und der nächste Schritt ist es ein allgemein gültiges Lösungsmodell zu erstellen. Ein solches Modell wird ``Pattern'' genannt.
meillo@30 252
meillo@28 253
meillo@28 254 \subsection{Überleitung}
meillo@30 255
meillo@30 256 Um unsere Lösung in das Pattern zu überführen bedarf es ein paar anderer Bezeichnungen:
meillo@28 257
meillo@30 258 \begin{itemize}
meillo@30 259 \item Pinnwand-Sekretärin-Einheit $\rightarrow$ ``Subject''
meillo@30 260 \item Die Zettel auf der Pinnwand $\rightarrow$ ``subjectState''
meillo@30 261 \item Interessenten $\rightarrow$ ``Observers''
meillo@30 262 \end{itemize}
meillo@11 263
meillo@11 264
meillo@30 265 Beim Programmieren sind besonders Interfaces (also Schnittstellen) wichtig. Diese entsprechen den Fähigkeiten die Pinnwand/Sekretärin und Interessenten haben oder anbieten. Dies wären zum Beispiel, dass Interessenten nicht taub sein dürfen, lesen und zur Pinnwand hingehen können müssen. Oder auch die leserliche Schrift der Sekretärin. (Siehe dazu auch die Erarbeitung der Pinnwand-Sekretärin.)
meillo@28 266
meillo@11 267
meillo@11 268
meillo@11 269
meillo@28 270 \subsection{UML-Diagramme}
meillo@30 271
meillo@30 272 Um das Pattern darzustellen bieten sich UML-Diagramme an.
meillo@30 273
meillo@28 274
meillo@28 275 \begin{figure}[hbt]
meillo@28 276 \centering
meillo@31 277 \includegraphics[width=8cm]{pics/observer_big.png}
meillo@28 278 \caption{Struktur-Diagramm des Observers}
meillo@28 279 \end{figure}
meillo@28 280
meillo@28 281
meillo@28 282
meillo@28 283 \begin{figure}[hbt]
meillo@28 284 \centering
meillo@31 285 \includegraphics[width=8cm]{pics/observer-interaction_big.png}
meillo@28 286 \caption{Interaktions-Diagramm des Observers}
meillo@28 287 \end{figure}
meillo@28 288
meillo@28 289
meillo@30 290 Wer den ersten Teil der Ausarbeitung verstanden hat und UML kann, sollte hier keine Probleme haben die Diagramme zu verstehen --- es ist quasi das Gleiche, nur in einer anderen Darstellungsform.
meillo@30 291
meillo@30 292
meillo@11 293
meillo@11 294
meillo@11 295 % Daten aus der Beschreibung des Observers von GoF
meillo@11 296 % in welche Gruppen wird er eingeordnet
meillo@28 297 \subsubsection{Klassifizierung nach GoF}
meillo@11 298
meillo@30 299 Die ``Gang of Four'' (sie formulierten die ersten Design-Patterns für die Informatik) habe ein einheitliches Schema zu ihrer Klassifizierung erstellt. Anhand diesem ist der Observer folgendermaßen einzuordnen:
meillo@30 300
meillo@28 301 \paragraph{Klassifizierung}
meillo@11 302 Verhaltensmuster, objektbasierend
meillo@28 303
meillo@11 304
meillo@28 305 \paragraph{Auch bekannt als}
meillo@11 306 Publish-Subscribe, Dependents
meillo@28 307
meillo@11 308
meillo@28 309 \paragraph{Zweck}
meillo@32 310 Abhängigkeiten zwischen Objekten erstellen, sodass sich abhängige Objekte ändern, wenn sich das Objekt selbst ändert.
meillo@11 311 % todo: besser formulieren
meillo@28 312
meillo@11 313
meillo@28 314 \paragraph{Kurzbeschreibung}
meillo@32 315 Schnittstellen anlegen, damit Abhängigkeiten zwischen Objekten registriert
meillo@11 316 werden können, und um die abhängigen Objekte über Zustandsänderungen zu
meillo@11 317 informieren.
meillo@11 318 % todo: Formulierung überdenken
meillo@28 319
meillo@11 320
meillo@11 321
meillo@11 322
meillo@28 323
meillo@28 324 \subsection{Beispiele für den Observer in der Praxis}
meillo@11 325 % Einsatzgebiete (MVC) und RL (Mailingslisten, Ebay-Suchabo)
meillo@11 326 % nicht aber (Blog + RSS)
meillo@11 327
meillo@30 328 Wo ist das Observer-Pattern nun im täglichen Leben anzutreffen? Natürlich ist hier das Leben in der digitalen Welt gemeint, schließlich geht es uns ja um ein Design-Pattern für die Programmierung.
meillo@11 329
meillo@30 330 Zuerst einmal ist anzuführen, dass der Observer ein sehr verbreitetes Design-Pattern ist, das recht häufig bei passenden Problemstellungen eingesetzt wird.
meillo@30 331
meillo@30 332 Primär wäre das alles was mit Model-View-Controller (kurz: MVC) zusammenhängt. MVC wird vor allem für grafische Oberflächen eingesetzt. Dabei fungiert das Model als Subject und die View als Observer. Der Controller ist eher von untergeordneter Bedeutung. (MVC ist übrigens ein Architektur-Pattern.)
meillo@30 333
meillo@30 334 Aber auch Mailinglisten und Such-Abos (wie bei Ebay) sind optimalerweise nach dem Observer-Pattern implementiert.
meillo@30 335
meillo@30 336
meillo@30 337 \textbf{Kein} Beispiel für das Observer-Pattern ist aber der Weblog mit RSS-Feed! Denn hier findet kein Abonnement-Vorgang statt, der Client (Observer) meldet sich nicht bei der Website (Subject) an, und bekommt auch keine Änderungsinformationen zugeschickt. Stattdessen ruft der Client nur Informationen ab, die die Website ständig zur Verfügung stellt. (vgl. Pinnwand ohne Sekretärin)
meillo@30 338
meillo@11 339
meillo@11 340
meillo@11 341
meillo@11 342
meillo@11 343
meillo@11 344
meillo@31 345
meillo@28 346 %\subsection{Erweiterungen}
meillo@28 347 %% Erweiterungen, verbleibende Probleme, Kompromisse beim Design
meillo@31 348 \subsection{Erweiterungen des Patterns}
meillo@11 349
meillo@31 350 \subsubsection{Ein Observer und mehrere Subjects}
meillo@31 351 Oft ist es nicht nur ein einziges Subject, das beobachtet werden soll. Damit ein Observer mehrere Subjects beobachten kann, muss er den Namen des Subjects mitsenden. So kann festgestellt werden welches Subject betroffen ist.
meillo@28 352
meillo@11 353
meillo@31 354 \subsubsection{Nur für bestimmte Informationen anmelden}
meillo@32 355 Eine weitere kleine Erweiterung ist die Anmeldung am Subject für nur bestimmte Informationen. Dies ist sicher auch eine Ergänzung die unsere Pinnwand verbesser hätte. So wäre es dann möglich gewesen sich nur für Zimmerangebote oder ähnliches anzumelden. So werden auch die unnötigen Updates verringert, was positiv auf die Performance wirken kann.
meillo@28 356
meillo@28 357
meillo@32 358 \subsubsection{ChangeManager}
meillo@32 359 Bei komplexen Update-Zusammenhängen ist es empfehlenswert einen ChangeManager zwischen die verschiedenen Subjects und Observers zu stellen. Dieser vermittelt dann zwischen den Beteiligten und koordiniert die Update-Vorgänge. Der ChangeManager ist eine Instanz vom Mediator-Pattern und üblicherweise Singleton, da normalerweise nur einer für alle Observer-Beziehungen verwendet wird.
meillo@28 360
meillo@28 361
meillo@31 362 \subsubsection{Wer ruft notify() auf?}
meillo@32 363 Dies kommt stark auf das Programm an. Beide Alternativen haben ihre Vor- und Nachteile:
meillo@28 364
meillo@31 365 \paragraph{Das Subject}
meillo@28 366 \begin{itemize}
meillo@28 367 \item[+] notify() wird sicher bei jedem setState() aufgerufen
meillo@28 368 \item[-] hohe Update-Kosten bei Änderungen en-block
meillo@28 369 \end{itemize}
meillo@28 370
meillo@28 371
meillo@31 372 \paragraph{Der Observer}
meillo@28 373 \begin{itemize}
meillo@28 374 \item[+] intelligenter Zeitpunkt des notify()-Aufrufs möglich
meillo@28 375 \item[-] der Client darf den notify()-Aufruf nicht vergessen
meillo@28 376 \end{itemize}
meillo@28 377
meillo@28 378
meillo@28 379
meillo@28 380
meillo@28 381
meillo@28 382
meillo@28 383
meillo@28 384
meillo@28 385
meillo@28 386
meillo@28 387
meillo@28 388
meillo@28 389
meillo@28 390 \newpage
meillo@33 391
meillo@11 392 \section{Zusammenfassung}
meillo@28 393 %\textbf{Zusammenfassend}
meillo@33 394
meillo@33 395 Ich habe in meiner Ausarbeitung bisher ganz bewusst auf Quellcode verzichtet, denn ich wollte vermitteln weshalb das Observer-Pattern so aufgebaut ist wie es ist. Ich wollte Verständnis für Design Patterns entwickeln und zeigen, dass sie absolut logische Lösungen sind.
meillo@33 396
meillo@33 397 Design Patterns sind dabei Modelle wie Quellcode aufgebaut werden sollte. Sie sind kein Code --- sie beschreiben nur wie Code sein sollte. Das ist auch ganz gut so, denn:
meillo@33 398
meillo@33 399 \begin{quote}
meillo@33 400 \textbf{ Implementierungen sind Schall und Rauch,\\
meillo@33 401 Konzepte dagegen bleiben bestehen! }
meillo@33 402 \end{quote}
meillo@33 403
meillo@33 404 Aus diesem Grund will ich mich mit Quelltext auf dieses Beispiel im Anhang beschränken. Dennoch finde ich es wichtig, doch zumindest eine Beispiel-Implementierung vorzeigen zu können, da Quellcode sehr aussagekräftig sein kann. In jeden Fall wird er meine sonstigen Ausführungen gut abrunden.
meillo@33 405
meillo@33 406
meillo@33 407 \paragraph{In drei Sätzen:}
meillo@28 408 \begin{itemize}
meillo@28 409 \item Menschen denken basierend auf der Realität
meillo@28 410 \item deshalb Design Patterns auf Realität zurückführen
meillo@28 411 \item Patterns anwenden weil man es in der Realität auch so machen würde
meillo@28 412 \end{itemize}
meillo@11 413
meillo@11 414
meillo@11 415
meillo@11 416
meillo@11 417
meillo@33 418 \appendix
meillo@11 419
meillo@33 420 \newpage
meillo@11 421
meillo@33 422 \section{Beispiel-Implementierung}
meillo@11 423
meillo@33 424 {\scriptsize
meillo@33 425 \lstinputlisting[language=java]{code/observer-example.java}
meillo@33 426 }
meillo@33 427 \flushright{ \tiny Quellcode von http://java2s.com }
meillo@33 428
meillo@33 429
meillo@33 430
meillo@33 431
meillo@33 432
meillo@33 433
meillo@33 434 \section{Verwendete Software}
meillo@11 435 \begin{itemize}
meillo@11 436 \item Debian GNU/Linux
meillo@32 437 \item \texttt{pdflatex}
meillo@11 438 \item Vim
meillo@11 439 \item qiv und ImageMagick
meillo@11 440 \item Mercurial
meillo@11 441 \end{itemize}
meillo@11 442
meillo@11 443
meillo@11 444
meillo@11 445
meillo@11 446
meillo@11 447
meillo@11 448 \end{document}