Design pattern
Command
(Action, Transaction)
Design pattern
Command
Command
(Action, Transaction)
Command Design Pattern
Kapselung von Anfragen als eigenständige Objekte
- GoF Pattern
- Entkopplung
- Undo / Redo
Inhaltsverzeichnis
- Was ist das Command Pattern?
- Wann wird es verwendet?
- Kernkomponenten
- Funktionsweise
- Praxisbeispiele
- Undo / Redo
- Vorteile & Nachteile
- Best Practices
1. Was ist das Command Pattern?
Das Command Pattern ist ein Verhaltensmuster, das eine Anfrage
als Objekt kapselt. Dadurch können Aktionen flexibel übergeben, gespeichert,
protokolliert oder später ausgeführt werden.
Statt einen Methodenaufruf direkt auszuführen, wird daraus ein eigenes Objekt,
das alle Informationen über die Aktion enthält.
Grundidee
- Trennung: Aufrufer und Ausführer einer Aktion werden entkoppelt
- Kapselung: Methode, Parameter und Empfänger werden in einem Objekt gespeichert
- Flexibilität: Aktionen können übergeben, verzögert oder rückgängig gemacht werden
2. Wann verwendet man das Command Pattern?
- GUI-Komponenten: Buttons, Menüs, Toolbar-Aktionen
- Job Queues: Aufgaben später oder asynchron ausführen
- Undo / Redo: Aktionen rückgängig machen
- Logging: Operationen speichern und erneut abspielen
Beispiele für den Einsatz
- Texteditoren mit Copy, Paste, Save, Undo
- Warteschlangen wie RabbitMQ oder Background Jobs
- Grafikprogramme mit Rückgängig-Funktion
- Smart-Home-Steuerungen und Fernbedienungen
3. Kernkomponenten
- Command – definiert die Schnittstelle, meist
execute()
- Concrete Command – konkrete Implementierung einer Aktion
- Receiver – führt die eigentliche Geschäftslogik aus
- Invoker – löst die Command aus
- Client – erstellt und verbindet alle Objekte
Die Rollen im Überblick
- Command: gemeinsamer Vertrag für alle Befehle
- Concrete Command: kennt Receiver und konkrete Aktion
- Receiver: enthält die eigentliche Logik
- Invoker: startet die Ausführung, ohne Details zu kennen
- Client: verdrahtet das System
4. Funktionsweise
- Der Client erstellt den Receiver
- Der Client erstellt ein Concrete Command mit dem Receiver
- Der Client übergibt das Command an den Invoker
- Der Invoker ruft
execute() auf
- Das Command delegiert die Arbeit an den Receiver
Wichtige Erkenntnis
Der Invoker kennt den Receiver nicht direkt.
Er kennt nur das Command Interface.
Genau diese Entkopplung macht das Pattern so flexibel und gut erweiterbar.
5. Praxisbeispiele
- GUI-Buttons: Jeder Button führt ein Command aus
- Texteditoren: Jede Änderung ist ein Command
- Datenbanktransaktionen: Operationen können gekapselt werden
- Fernbedienungen: Ein Knopf steuert verschiedene Geräte
Restaurant-Beispiel
- Kellner = Invoker
- Bestellung = Command
- Küche = Receiver
Der Kellner kocht nicht selbst, sondern gibt die Bestellung an die Küche weiter.
Genau so delegiert der Invoker die Aktion an den Receiver.
6. Undo / Redo
Ein großer Vorteil des Command Patterns ist die Unterstützung von
Undo und Redo.
- Jede Aktion wird als Command gespeichert
- Die Historie wird meist in Stacks verwaltet
- Ein Command kann neben
execute() auch undo() besitzen
Typischer Ablauf bei Undo / Redo
- Vor der Ausführung wird der relevante Zustand gespeichert
- Nach
execute() landet das Command im Undo-Stack
- Bei Undo wird das letzte Command zurückgenommen
- Bei Redo wird es erneut ausgeführt
7. Vorteile
- Lose Kopplung zwischen Sender und Empfänger
- Erweiterbarkeit durch neue Commands ohne Änderungen am Kernsystem
- Undo / Redo lässt sich gut integrieren
- Queueing und Logging von Aktionen ist einfach möglich
- Makro-Kommandos können mehrere Aktionen zusammenfassen
8. Nachteile
- Es entstehen oft viele kleine Klassen
- Für einfache Projekte kann das Pattern zu komplex sein
- Undo erfordert sauberes Zustandsmanagement
- Große Command-Historien können Speicher verbrauchen
- Nicht jede Aktion mit Seiteneffekten ist leicht rückgängig zu machen
Best Practices
- Jede Command sollte nur eine Aufgabe haben
- Commands möglichst immutable gestalten
- Factories oder Builder für komplexe Commands verwenden
- Seiteneffekte klar dokumentieren
- Ein Null Command vermeidet Null-Prüfungen
Einfaches Java-Beispiel
public interface Command {
void execute();
void undo();
}
Konkrete Commands implementieren dieses Interface und rufen die passende Methode des Receivers auf.
Fazit
Das Command Pattern kapselt Aktionen als Objekte und sorgt damit für
Entkopplung, Erweiterbarkeit und Kontrolle.
- Sender und Empfänger werden getrennt
- Aktionen werden flexibel steuerbar
- Undo, Redo, Logging und Queueing werden erleichtert