Karriere
Wissen
Über uns
29. Sep 2025
Design-Patterns helfen, komplexe Probleme elegant zu lösen. Anti-Patterns zeigen uns, wie man es besser nicht macht. In unserem Mentoring-Programm haben wir häufig auftretende Patterns zusammengetragen und klären kurz über deren Sinn und Unsinn auf.
Jede Entwicklerin und jeder Entwickler steht früher oder später vor den gleichen Fragen: Wie strukturiere ich meinen Code sinnvoll? Wie halte ich Projekte flexibel, wartbar und erweiterbar? Hier kommen Design-Patterns ins Spiel – bewährte, wiederverwendbare Lösungen für typische Herausforderungen in der Softwareentwicklung. Sie unterstützen gute Architektur, fördern die Teamkommunikation und steigern die Codequalität.
Gleichzeitig gibt es Anti-Patterns: Ansätze, die zwar gut gemeint sind, aber schnell zu schlechter Praxis führen können – und zeigen, wie man diese Fallen vermeidet.
Grundsätzlich zeichnet sich gutes Software-Design durch Klarheit, Einfachheit und Wiederverwendbarkeit aus. Die Beachtung von Grundprinzipien helfen dabei, sauberen, verständlichen und wartbaren Code zu entwickeln. Zu beachten sind: SOLID, DRY und KISS.
Prinzip: SOLID ist ein Satz von fünf objektorientierten Designprinzipien, der Software so strukturiert, dass sie wartbar, erweiterbar und robust gegenüber Änderungen bleibt. Mehr dazu in unserem News-Artikel .
Prinzip: Jedes Stück Wissen sollte eine einzige, eindeutige Repräsentation im System haben.
Prinzip: Systeme funktionieren am besten, wenn sie einfach gehalten sind. Vermeide unnötige Komplexität.
Klassische Design-Patterns sind bewährte Lösungsansätze für wiederkehrende Probleme in der Softwareentwicklung. Sie dienen als Schablonen, die helfen, Code verständlicher, wartbarer und erweiterbarer zu gestalten.
Sie lassen sich grob in drei Kategorien einteilen:
Creational: Strategien zur Objekterstellung, die Instanziierung kapseln und Abhängigkeiten reduzieren.
Structural: Konzepte zum Zusammenspiel von Klassen und Objekten, um Strukturen flexibel und wartbar zu halten.
Behavioral: Muster für die Zusammenarbeit von Objekten und die Verteilung von Verantwortungen und Algorithmen.
Wir stellen folgende Design-Patterns kurz vor:
Motivation: Oft müssen mehrere Objekte automatisch informiert werden, wenn sich der Zustand eines anderen Objekts ändert. Möchte man eine harte Kopplung vermeiden, dann bietet sich das Observer-Pattern an, da das beobachtete Objekt sein Empfänger nicht kennen und auch nicht direkt ansprechen muss.
Beschreibung: Das Observer-Pattern stellt eine Eins-zu-Viele-Abhängigkeit zwischen Objekten her, bei der mehrere «Observer-Objekte» benachrichtigt werden, wenn das «Subjekt» seinen Status ändert. Es wird häufig für die Ereignisbehandlung und die Implementierung von Abonnementmodellen verwendet.
Anwendungsfälle:
Motivation: Die Logik zum Erzeugen von Objekten soll flexibel bleiben, ohne den aufrufenden Code ändern zu müssen. Das Instanziieren eines Objektes wird von der restlichen Logik getrennt.
Beschreibung: Das Pattern der Factory-Methode definiert eine Schnittstelle zum Erstellen von Objekten, lässt jedoch Unterklassen entscheiden, welche Klasse instanziiert werden soll.
Motivation: Manchmal gibt es für bestimmte Aufgaben mehrere Lösungsstrategien und man möchte dynamisch entscheiden, welcher Ansatz gewählt werden soll. Anstatt dies im Code fest zu verdrahten, bietet das Strategy-Pattern hier Abhilfe.
Beschreibung: Das Strategy-Pattern definiert eine Familie von Algorithmen, kapselt jeden einzelnen und macht sie austauschbar. Der Client kann den zu verwendenden Algorithmus dynamisch auswählen, ohne den Code des Clients zu ändern.
Motivation: Systeme müssen oft mit bereits bestehenden oder fremden Systemen interagieren, die nicht immer zusammenpassen. Ein Adapter übersetzt zwischen diesen Welten.
Beschreibung: Das Adapter Pattern konvertiert die Schnittstelle einer Klasse in eine andere Schnittstelle, die ein Client erwartet. Es ermöglicht die Zusammenarbeit von ansonsten inkompatiblen Schnittstellen.
Motivation: Bestehende Klassen benötigen zusätzliche Funktionalitäten, sollen aber intern nicht verändert werden und auch eine komplexe Vererbungshierarchie ist nicht gewünscht. Unter diesen Bedingungen lohnt es sich, das Decorator-Pattern in Betracht zu ziehen.
Beschreibung: Das Decorator-Pattern fügt einem Objekt dynamisch zusätzliche Funktionen hinzu. Es ist nützlich, um das Verhalten von Objekten zu erweitern, ohne ihre Struktur zu ändern.
Motivation: Aktionen in einem System sind meist sehr flüchtig und nicht einfach nachzuvollziehen. Wenn man unterschiedliche Aktionen als eigene Objekte ansieht, dann bietet dies diverse Vorteile.
Beschreibung: Das Command-Pattern kapselt eine Anforderung als Objekt und ermöglicht es so, Methoden mit Anforderungen, verzögerter Ausführung oder Warteschlangenanforderungen zu parametrisieren. Es ermöglicht die Funktion «Rückgängig» und «Wiederholen».
Motivation: Bei komplexen Objekten mit vielen optionalen Parametern kann die Konstruktion schnell unübersichtlich werden, vor allem wenn mehrere Build-Steps involviert sind, welche Abhängigkeiten zueinander aufweisen.
Beschreibung: Das Builder-Pattern trennt die Konstruktion eines komplexen Objekts von seiner Darstellung, sodass mit demselben Konstruktionsprozess unterschiedliche Darstellungen erstellt werden können. Es ist nützlich, um Objekte mit vielen optionalen Parametern zu erstellen.
Motivation: Direkter Zugriff auf ein Objekt ist manchmal nicht sinnvoll oder zu teuer – etwa wenn es geschützt, verzögert geladen oder überwacht werden soll.
Beschreibung: Das Proxy-Pattern wird verwendet, um den kontrollierten Zugriff auf ein Objekt zu ermöglichen. Dies kann in Szenarien wie Zugriffssteuerung, verzögerter Initialisierung oder Protokollieren von Aufrufen des Objekts nützlich sein.
Motivation: Wenn die Erzeugung neuer Objekte sehr aufwendig oder komplex ist, kann es unter Umständen einfacher sein bereits vorhandene Instanzen zu kopieren.
Beschreibung: Das Prototype-Pattern wird verwendet, wenn das Erstellen neuer Instanzen einer Klasse teuer ist. Anstatt Objekte von Grund auf neu zu erstellen, wird ein vorhandenes Objekt geklont.
Motivation: Viele direkt verknüpfte Objekte führen schnell zu unübersichtlichen Abhängigkeiten und «Spaghetti-Code» ( mehr dazu in den Anti-Patterns ). Mediator schafft hier eine zentrale Koordination.
Beschreibung: Das Mediator-Pattern fördert eine lose Kopplung, indem es die direkte Kommunikation zwischen Objekten verhindert. Stattdessen kommunizieren Objekte über den Mediator.
Motivation: Objekte verhalten sich häufig abhängig von ihrem internen Zustand unterschiedlich. Lange if/else- oder switch-Ketten machen den Code unübersichtlich und fehleranfälliger.
Beschreibung: Mit dem State-Pattern kann ein Objekt sein Verhalten in Abhängigkeit von seinem Zustand dynamisch ändern. Es kapselt zustandsspezifisches Verhalten in verschiedene Klassen.
Motivation: Es soll dieselbe Funktion gleichermassen auf Einzelobjekte, als auch auf eine Gruppe von Objekten anwendbar sein. Dadurch lassen sich Ganzteilhierarchien darstellen.
Beschreibung: Das Composite-Pattern wird verwendet, um einzelne Objekte und Kompositionen von Objekten einheitlich zu behandeln. Es eignet sich hervorragend für Systeme, die hierarchische Strukturen wie Dateisysteme erfordern.
Motivation: Manche Komponenten oder Klassen sollen in einem System genau einmal existieren und global zur Verfügung stehen.
Beschreibung: Das Singleton-Pattern beschränkt die Instanziierung einer Klasse auf eine einzelne Instanz und stellt einen globalen Zugriffspunkt darauf bereit. Es wird häufig für die Verwaltung freigegebener Ressourcen wie Konfigurationseinstellungen oder Datenbankverbindungen verwendet.
Motivation: Eine Anfrage kann potenziell von mehreren Objekten bearbeitet werden. Der Sender soll aber nicht wissen müssen, welches Objekt dafür zuständig ist.
Beschreibung: Das Pattern Chain-of-Responsibility ermöglicht es mehreren Objekten, Anforderungen zu verarbeiten, ohne jedoch zu wissen, welches Objekt sie verarbeiten wird.
Anti-Patterns sind scheinbar nützliche, aber langfristig problematische Lösungsansätze in der Softwareentwicklung. Sie entstehen oft aus Zeitdruck, mangelnder Erfahrung oder dem Versuch, schnelle Ergebnisse zu erzielen. Auf den ersten Blick wirken sie praktisch, führen jedoch zu schwer wartbarem, ineffizientem oder fehleranfälligem Code.
Wir stellen folgende Anti-Patterns kurz vor:
Schlechte Klassen sind Klassen mit unscharfen Verantwortlichkeiten, schlechtem Namenskonzept oder zu starker Abhängigkeit von anderen Klassen.
Mit Spaghetti-Code ist unstrukturierter, verschachtelter Code ohne klare Architektur oder Modularisierung gemeint.
Bei der Copy-Paste-Programmierung wird Code dupliziert statt wiederverwendbar gemacht.
Wenn das Singleton-Pattern inflationär eingesetzt wird, wodurch enge Kopplung, versteckte Abhängigkeiten und Testprobleme entstehen, spricht man von «Singleton Abuse».
Beim anämischen Domänenmodell enthalten Klassen im Domänenmodel nur Daten (Getter/Setter), aber keine fachliche Logik – dies führt zu einer prozeduralen statt objektorientierten Architektur.
Big Ball of Mud bezeichnet eine unstrukturierte Architektur ohne klare Trennung von Verantwortlichkeiten – alles wächst ungeplant zusammen.
Charakteristiken:
Ein vertrautes Werkzeug oder Framework wird für jedes Problem eingesetzt, unabhängig davon, ob es geeignet ist – «Ich kenne JavaScript, also werde ich Node.js für alles verwenden»:
Charakteristische Anzeichen:
Projekte mit unrealistischen Zielen, die praktisch zum Scheitern verurteilt sind.
Endlose Analyse und Planung verhindern den tatsächlichen Start oder Fortschritt der Entwicklung.
Ablehnung externer Lösungen oder bewährter Bibliotheken, nur weil sie nicht selbst entwickelt wurden – führt zu unnötiger Doppelarbeit.
Vorgehensweisen oder Technologien werden übernommen, ohne ihr Warum oder ihre Funktionsweise zu verstehen – «Ich habe gehört, dass wir Entwurfs-Pattern verwenden sollten.»
Die Architektur oder der Code wird optimiert, bevor klar ist, ob die Optimierung überhaupt nötig ist.
Patterns sind mehr als Theorie – sie sind Werkzeug, Sprache und Sicherheitsnetz für Entwicklerteams. Vom Observer bis zum Mediator: Wer die Muster kennt, kann Software stabiler und flexibler gestalten. Genauso wichtig ist es aber, Anti-Patterns frühzeitig zu erkennen und durch bewusste Architekturentscheidungen zu vermeiden.
• refactoring.guru – Design Patterns • SourceMaking – Design Patterns erklärt
Elements of Reusable Object-Oriented Software
Autoren: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides («Gang of Four») ISBN: 978-0-201-63361-0
Noch mehr Klarheit in deinem Code? In unserem News-Artikel erfährst du, wie du mit den SOLID-Prinzipien deine Software wartbar und skalierbar gestaltest.
Danke für Ihr Interesse an Cudos. Ihre Angaben werden vertraulich behandelt – den Newsletter können Sie jederzeit abbestellen.