Design Patterns
Design Patterns sind erprobte Lösungen für wiederkehrende Entwurfsprobleme. Sie sind kein Selbstzweck, sondern ein gemeinsames Vokabular - und wenn eine einfache Methode reicht, ist ein Pattern zu viel.
Ansicht
01
Verstehen
Lies die Kernidee und das Beispiel.
02
Prüfen
Beantworte die Aktiv-Checks.
03
Anwenden
Setze die Transferaufgabe um.
Mini-Erfolg
Du hast Strategy, Factory und Observer in einem kleinen Beispiel erkannt und einen davon selbst gebaut.
Warum das wichtig ist: Patterns sind erprobte Lösungen für wiederkehrende Probleme. Wer sie kennt, versteht fremden Code schneller und diskutiert über Lösungen statt über Geschmack.
Das darf schwer sein
Das ist ein Fortgeschrittenen-Thema. Lies es einmal in Ruhe, baue das Mini-Projekt und komm später zurück. Du musst es nicht sofort können.
Vorher hilfreich
Lerninhalt
Verstehen & anwenden
Strategy: Verhalten austauschen
Strategy kapselt austauschbares Verhalten hinter einem Interface.
Statt Vererbung oder langer if-Ketten übergibst du dem Objekt die passende Strategie.
Weil funktionale Interfaces nur eine Methode haben, darf eine Strategie auch ein Lambda sein - praktisch für kurze Regeln.
interface Versand {
double kosten(double gewicht);
}
class ExpressVersand implements Versand {
public double kosten(double gewicht) {
return 9.99 + gewicht * 0.5;
}
}
class Warenkorb {
private final Versand versand;
Warenkorb(Versand versand) {
this.versand = versand;
}
double versandkosten(double gewicht) {
return versand.kosten(gewicht);
}
}
// Als Lambda:
Versand pauschal = gewicht -> 4.99;Factory: Erzeugung kapseln
Eine Factory entscheidet an einer Stelle, welche Implementierung entsteht.
Der Aufrufer kennt nur das Interface und muss die konkrete Klasse nicht importieren.
Das lohnt sich, wenn die Auswahl von Konfiguration, Plattform oder Eingaben abhängt. Für ein einzelnes new ist eine Factory meist zu viel.
interface Zahlung {
void bezahle(double betrag);
}
class ZahlungFactory {
static Zahlung fuer(String art) {
return switch (art) {
case "karte" -> new KartenZahlung();
case "paypal" -> new PayPalZahlung();
default -> throw new IllegalArgumentException(
"Unbekannte Zahlungsart: " + art);
};
}
}Observer: Änderungen verteilen
Der Observer entkoppelt eine Quelle von beliebig vielen Empfängern.
Die Quelle kennt nur das Beobachter-Interface und ruft alle registrierten Beobachter bei einer Änderung auf.
In Java begegnet dir das Muster als Listener, zum Beispiel bei Events oder Property-Change-Listenern. Ein Consumer<String> reicht für ein kleines Beispiel.
import java.util.*;
import java.util.function.Consumer;
class Newsletter {
private final List<Consumer<String>> abonnenten = new ArrayList<>();
void abonnieren(Consumer<String> abonnent) {
abonnenten.add(abonnent);
}
void veroeffentlichen(String text) {
abonnenten.forEach(abonnent -> abonnent.accept(text));
}
}
Newsletter news = new Newsletter();
news.abonnieren(text -> System.out.println("Mail: " + text));
news.abonnieren(text -> System.out.println("Push: " + text));Vertiefung
Vom Problem zum Pattern
Ein Pattern ist keine Lösung, die man importiert. Du erkennst zuerst das Problem - zum Beispiel "mehrere Varianten desselben Verhaltens" - und wählst dann die kleinste Struktur, die es löst. Strategy nimmt Komposition, Factory nimmt die Erzeugung heraus, Observer verteilt Ereignisse.
Patterns haben Kosten: zusätzliche Klassen, Interfaces und Indirektion. Ein Singleton wird schnell zum globalen Zustand und erschwert Tests. Prüfe immer, ob eine einfache Methode oder ein Konstruktorparameter reicht.
interface Rabatt {
double berechne(double summe);
}
static Rabatt rabattFuer(String art) {
return switch (art) {
case "treue" -> summe -> summe * 0.9;
case "aktion" -> summe -> summe - 5;
default -> summe -> summe;
};
}Merksatz: Wähle das Pattern nach dem Problem, nicht nach dem Katalog. Wenn die einfache Lösung lesbar bleibt, ist sie meist die bessere.
Übungsaufgabe
Benachrichtigungen mit Observer
Baue einen Newsletter, an den sich beliebig viele Beobachter anhängen können. Veröffentliche eine Nachricht und zeige, dass Mail- und Push-Ausgabe unabhängig reagieren.
Das soll dein Programm können
- Interface Beobachter mit aktualisiere(String)
- Newsletter verwaltet eine Liste von Beobachtern
- Zwei Beobachter-Implementierungen
- Newsletter kennt keine konkrete Ausgabe
Schreibe den Code hier oder in deiner IDE und vergleiche ihn dann mit der Lösung.
Dein Code wird automatisch auf diesem Gerät gespeichert.
Hinweis anzeigen
In veroeffentlichen reicht eine Schleife über die Liste und b.aktualisiere(nachricht). Die beiden Implementierungen geben unterschiedliche Texte aus.
Lösung anzeigen
import java.util.*;
interface Beobachter {
void aktualisiere(String nachricht);
}
class MailBeobachter implements Beobachter {
public void aktualisiere(String nachricht) {
System.out.println("Mail: " + nachricht);
}
}
class PushBeobachter implements Beobachter {
public void aktualisiere(String nachricht) {
System.out.println("Push: " + nachricht);
}
}
class Newsletter {
private final List<Beobachter> beobachter = new ArrayList<>();
void abonnieren(Beobachter b) {
beobachter.add(b);
}
void veroeffentlichen(String nachricht) {
for (Beobachter b : beobachter) {
b.aktualisiere(nachricht);
}
}
}
public class NewsletterDemo {
public static void main(String[] args) {
Newsletter newsletter = new Newsletter();
newsletter.abonnieren(new MailBeobachter());
newsletter.abonnieren(new PushBeobachter());
newsletter.veroeffentlichen("Neue Java-Lektion online");
}
}Warum funktioniert das?
Der Newsletter kennt nur das Interface und weiß nicht, ob eine Mail, ein Push oder ein Log entsteht. Ein neuer Kanal ist eine neue Klasse - die Quelle bleibt unverändert.
Aktiv-Check
Teste dein Verständnis
Erkennen: Welcher Abschnitt passt?
Welcher Abschnitt passt zu diesen Begriffen?
Spaßprojekt
Versand und Zahlung austauschbar
Baue einen kleinen Checkout mit austauschbaren Versandarten (Strategy) und einer Factory für Zahlungsarten. Ergänze eine neue Variante, ohne bestehenden Code zu ändern.
Selbstcheck
Kann ich das schon?
Hake ab, was du wirklich erklären oder selbst bauen könntest.
Fortschritt
Bereit zum Abschließen?
Markiere die Lektion als abgeschlossen, um XP und Streak zu erhalten.