Begriff
Design Patterns
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Architekten haben Muster: "Wenn du ein Dach baust, nutze Dreiecke, die sind stabil." Programmierer haben auch Muster. Es sind bewährte Lösungen für wiederkehrende Probleme. Statt das Rad neu zu erfinden, sagst du: "Wir brauchen hier eine Factory." Jeder Kollege weiß sofort, was gemeint ist (gemeinsame Sprache). Die berühmtesten kommen aus dem Buch der "Gang of Four" (GoF).
Merksatz: Wiederverwendbare Lösungsschablonen für häufig auftretende Probleme in der Softwarearchitektur.
Die 3 Kategorien:
- Erzeugung (Creational): Wie werden Objekte geboren? (Singleton, Factory, Builder).
- Struktur (Structural): Wie werden Objekte zusammengesteckt? (Adapter, Decorator, Facade).
- Verhalten (Behavioral): Wie reden Objekte miteinander? (Observer, Strategy, Iterator).
1. Singleton (Der verhasste Klassiker)
"Es darf nur EINE Instanz geben (z. B. Datenbank-Verbindung)."
Code: Database.getInstance().
Problem: Es ist globaler Zustand. Schwer zu testen (Mocking). Gilt heute oft als Anti-Pattern. Besser: Dependency Injection.
2. Observer (Reaktives Programmieren)
"Wenn sich X ändert, sag allen Bescheid." Youtube-Kanal (Subject) -> Abonnenten (Observers). Grundlage für Moderne UIs (React, RxJS) und Event-Driven Architecture.
3. Factory vs. Strategy
- Factory: Kapselt die Erstellung. "Gib mir ein Auto" -> Factory entscheidet, ob Golf oder Porsche.
- Strategy: Kapselt den Algorithmus. "Berechne Route" -> Strategy entscheidet, ob "Schnellste", "Kürzeste" oder "Öko". Man kann den Algorithmus zur Laufzeit tauschen.
Die Entwicklung (Von GoF zu Cloud-Native)
Die klassischen "Gang of Four" (GoF) Patterns bezogen sich streng auf Objekt-Instanzen innerhalb desselben Speichers (RAM) eines Monolithen. In der Cloud-Native Welt (Microservices, K8s) haben sich die Problemstellungen verschoben. Heutige Architectural Patterns drehen sich um verteilte Systeme. Typische Beispiele:
- Sidecar Pattern: Ein Hilfs-Container, der logless neben der App im selben Pod läuft (z.B. Envoy Proxy im Service Mesh), um Netzwerk und Security zu proxien, ohne den Code anzufassen.
- Circuit Breaker: Ein Schutzschalter. Schlägt Service A dreimal beim Aufrufen von Service B fehl, öffnet der Oberserver den Kreislauf. Aufrufe scheitern fortan sofort (Fast Fail), um das Backend-System nicht durch Retries zu überlasten ("Thundering Herd"), bis ein Healthcheck grünes Licht gibt.
- Saga Pattern: Der Gegenentwurf zu zweistufigen Datenbank-Transaktionen (2PC) im Microservice-Orchester. Transaktionen werden asynchron abgehandelt (Order Created -> Event -> Payment Charged).
Dependency Injection (DI) & IoC Container
Das wohl mächtigste Pattern in der modernen Enterprise-Software (Spring Boot, Angular, .NET Core) ist die Inversion of Control (IoC), meist implementiert als Dependency Injection.
Statt eine Factory hart im Code aufzurufen (var db = new MySQLFactory()), reicht eine Klasse ihre Abhängigkeiten nur als Interfaces an den Konstruktor durch.
Beim Start der Applikation baut ein Framework-Magier (der DI-Container) den gesamten "Abhängigkeits-Baum" auf und reicht die Objekte hinein.
Das Ergebnis: Extrem entkoppelter, modulare Komponenten, bei der du das Modul MySQL durch MockSQL für Unit-Tests mit exakt Null Code-Änderungen an der eigentlichen Business-Logik austauschen kannst.
Das State-Transition-Anti-Pattern
Oft verbirgt sich unter wild wuchernden if-else-Ketten (Code Smell) das Fehlen des State Patterns.
Wenn ein Objekt (Order) verschiedene Zustände hat (New, Paid, Shipped, Canceled), prüfen Entwickler bei jedem Funktionsaufruf: if state == Paid do X else do Y. Ziemlich bald hat die Klasse 2000 Zeilen und wird ungewartbar.
Das State Pattern teilt das Objekt in mehrere, polymorphe Subklassen auf (PaidState, ShippedState), welche das State-Interface implementieren.
Das ursprüngliche Objekt delegiert nur noch an sein State-Property. Ändert sich der Status, überschreibt man schlicht die Instanz (this.state = new ShippedState()).
Quick-Check
Anti-Pattern?
Ein Muster, das oft genutzt wird, aber schlecht ist. (z. B. "God Object" - eine Klasse, die alles macht).Over-Engineering?
Die Gefahr bei Patterns. Anfänger klatschen überall Patterns drauf, wo ein einfachesifreichen würde. "Keep it simple, stupid" (KISS) schlägt Patterns.Adapter Pattern?
Wie ein Reise-Stecker-Adapter. Du hast eine Klasse mit Interface A, brauchst aber Interface B. Der Adapter übersetzt dazwischen.