Patterns

Patterns im Detail

Arten von Mustern

Patterns gibt es auf diversen Abstraktionsebenen und für alle möglichen Arten von Problemen:

  • Architekturpatterns (architectural patterns), teilweise auch „Architekturstile“ (architectural styles) genannt
  • Analysepatterns (analysis patterns)
  • Entwurfsmuster (design patterns); das sind wohl die bekanntesten
  • Code-Patterns, so genannte Idiome (idioms)
  • Anti-Patterns, die häufig anzutreffende schlechte Lösungen beschreiben
  • Code Smells, die quasi Anti-Patterns auf Codeebene darstellen

Die Unterscheidung ist dabei manchmal nicht ganz klar. Manche machen auch einen Unterschied zwischen Architekturmustern und Architekturstilen. Darüber hinaus existiert ein fließender Übergang zwischen den einzelnen Kategorien. So wird MVC teilweise als Architekturmuster, wie auch als Entwurfsmuster betrachtet. Und RAII kann man sowohl als Entwurfsmuster als auch als Idiom sehen. Man könnte auch sagen, man kann manche Muster einfach auf verschiedenen Abstraktionsebenen anwenden. Wendet man ein Muster auf Architekturebene an, ist es ein Architekturmuster, benutzt man es hingegen „nur“ im Kleinen, d.h. im Entwurf, ist es ein Entwurfsmuster.

Architekturmuster beschreiben den fundamentalen Aufbau einer Software. Sie definieren, wie man von der Software denkt. Denn auch das ist grundlegendes Merkmal von Patterns: Sie helfen dabei, bestimmte Ideen und Konzepte zu kommunizieren. Das erkennt man bei Architekturmustern ganz deutlich. Beispiele für Architekturmuster sind Client-Server oder auch Layers. Wenn man ein Client-Server-System aufbaut und das Client-Server-Pattern anwendet, dann *denkt* man vom System als Client-Server-System. Auf der anderen Seite kann man auch Client-Server-Systeme aufbauen, ohne von vorne herein in dieser Unterscheidung zu denken, indem man die Verteilung auf Client und Server erst später betrachtet. Das ist z.B. dann der Fall, wenn man ein System als distributed object system begreift (sowas lässt sich beispielsweise mit RMI oder CORBA realisieren). In diesem Fall denkt man vom System als Ansammlung verteilter Objekte und so ist das quasi das vorherrschende Architekturmuster bzw. der Architekturstil. Client-Server wäre in diesem Fall nur eine Art „Verteilungsmuster“ (wenn man das so betrachten möchte).

Analysemuster hingegen betreffen die fachliche Modellierung und beschreiben wie sich fachliche Konzepte mit Klassen bzw. Objekten abbilden lassen. Es geht hierbei nicht um technische Lösungen, sondern lediglich um die Modellierung fachlicher Zusammenhänge. Das Account-Muster beschreibt beispielsweise wie man Bankkonten und ähnliche Konzepte modellieren kann.

Entwurfsmuster beschreiben konkrete technische Lösungen. So beschreibt das Observer-Pattern beispielsweise, wie man eine beliebige Anzahl an (unbekannten) Objekten über ein Ereignis benachrichtigen kann. An diesem Beispiel sieht man auch recht gut, wie ein Pattern auf unterschiedlichen Abstraktionsebenen angewendet werden kann. Wendet man das Observer-Pattern an, um die Kommunikation einzelner Objekte zu realisieren, ist es ein Entwurfsmuster. Macht man es hingegen zum generellen Prinzip der Kommunikation in der Software, denkt man also vom System nur in Objekten, die sich gegenseitig Ereignisse signalisieren, wird das Muster zum Architekturmuster. In diesem Fall nennt man es meist Publish-Subscribe.

Idiome sind sprachabhängige Codemuster. Manches kann man auf unterschiedliche Art und Weise lösen und in manchen Sprachen ist die eine Art und Weise die vorherrschende, und in anderen Sprachen wird es typischerweise anders gemacht. Das kann technische Gründe (wie verschiedene Sprachfeatures) haben oder auch gewachsene „Sprachkultur“ sein. In ersterem Fall hat das Idiom handfeste technische Vorteile, aber auch in letzterem Fall, sollte man dem Idiom folgen, weil die Realisierung dadurch, dass andere Entwickler diese Art der Herangehensweise kennen und erwarten, besser verständlich wird. Ein einfaches Beispiel wäre das iterieren über eine Liste oder ein Array. Man kann dazu verschiedene Arten von Schleifen einsetzen, Iteratoren verwenden, oder höherwertige Funktionen. Ein Beispiel für ein Idiom, das in gewissen Sprachfeatures begründet ist, ist das RAII-Idiom in C++. In C++ gibt es keine try..finally-Blöcke, dafür aber Stackobjekte. Das RAII-Pattern beschreibt nun, wie man auch damit zuverlässig Objekte freigeben kann.

Anti-Patterns sind im Gegensatz zu „normalen“ Pattern schlecht ausbalancierte Kräfte bzw. Namen für typische Fehler und Schwächen einer Realisierung oder eines Prozesses. Sie dienen hauptsächlich dazu, Probleme beim Namen nennen zu können. Ein Beispiel für ein typisches Anti-Pattern ist die Gottklasse (auch Gottobjekt, god class oder god object genannt). Dieses Muster beschreibt eine Klasse, die zu viel weiß und zu viel tut. Sie ist unnötig kompliziert und erhöht außerdem die Kopplung in einem System und erschwert damit Wiederverwendung und Wartung.

Auf Code-Ebene nennt man Anti-Patterns Code-Smells. Ein Beispiel dafür wäre eine zu lange Methode.

Darüber hinaus gibt es noch viele weitere Bereiche in denen Patterns verwendet werden. Das reicht von GUI-Design bis Projektorganisation. Das generelle Prinzip der Patterns ist universell anwendbar.

Patterns als Workarounds

Manche argumentieren, dass Patterns nichts weiter sind als Workarounds für fehlende Sprachfeatures. So ganz teile ich diese Ansicht nicht, aber dennoch steckt darin ein wahrer Kern. Denn in der Tat gibt es in manchen Programmiersprachen Features, die manche Patterns teilweise überflüssig machen oder quasi „unter einer Syntax-Decke verschwinden lassen“ und umgekehrt nutzt man gewisse Patterns, wenn man diese Features nicht hat. So kann man beispielsweise das Visitor-Pattern benutzen, wenn man eine Sprache verwendet, die kein Multiple Dispatch kennt. Und in C# braucht man für Events zu realisieren keine Observer, weil man dort Multicast-Delegates hat.

Auf ähnliche Weise könnte man auch alltägliche Sprachkonstrukte wie Schleifen und if-then-else-Konstrukte als Patterns sehen, die durch Syntax ersetzt wurden. Und in der Tat muss man diese Konstrukte in Assembler immer wieder selbst nachbauen. Man könnte so die strukturierte Programmierung quasi als Mustersprache mit den drei Patterns Sequenz, Auswahl und Wiederholung betrachten. Und bei Wiederholung könnte man die drei Pattern-Varianten „kopfgesteuerte Schleife“, „fußgesteuerte Schleife“ und „Zählschleife“ definieren. In Assembler sind das Patterns (Idiome); in Hochsprachen hingegen sind es eingebaute Sprachfeatures.

Teilweise wird so argumentiert, dass Patterns nur Symptome fehlender Sprachfeatures sind. IMHO trifft das jedoch nicht auf alle Patterns und alle Anwendungen von Patterns zu. Dennoch erkennt man hier eine gewisse Sprachabhängigkeit mancher Patterns.

Kapitel: | Zurück | 1 | 2 | 3 | 4 | 5 | 6 | Weiter |

3 Kommentare


  1. > _In_ meinen Augen vermischen diese Definitionen jedoch oft

    Typo.


  2. > Außerdem muss bei Änderung der GUI die _ChatClient_-Klasse angepasst werden

    Typo.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert