Zurück zu den Artikeln
📄
Command patterndesign patternundoinvokerreceivermacroqueuesoftware architecture

Was ist das Command Pattern und wann sollte man es verwenden?

Verwandeln Sie Aktionen in erstklassige Objekte, um sie einzureihen, zu protokollieren, rückgängig zu machen oder zu wiederholen, ohne Aufrufer an Implementierungen zu binden. Das Command-Pattern trennt Auslöser sauber von der Ausführung.

Was ist das Command Pattern und wann sollte man es verwenden?

Das Command Pattern stellt eine Anfrage als Objekt dar, wodurch Aktionen parametrisiert, eingerichtet, protokolliert, wiederholt oder rückgängig gemacht werden kann, ohne dass Auslöser und Empfänger eng gekoppelt sind.

Die Grundidee

interface Command {
  execute(): void;
  undo(): void;
}

const command = new BoldCommand(editor);
manager.execute(command);
manager.undo();

Der Manager kennt lediglich das Interface des Commands und muss weder die Details der Textbearbeitung noch die der Dateilöschung kennen. Dadurch bleibt er flexibel, weil er jede konkrete Implementierung austauschen kann, ohne selbst etwas davon zu wissen.

Die Beteiligten

  • Command: definiert die Operationen execute und, sofern sinnvoll, undo.
  • Konkretes Command: hält den Empfänger sowie die für die Ausführung nötigen Anfragedaten.
  • Invoker: führt Commands aus und kann dabei eine Historie führen.
  • Empfänger: führt die eigentliche Arbeit aus.
class CommandManager {
  private history: Command[] = [];

  execute(command: Command) {
    command.execute();
    this.history.push(command);
  }

  undo() {
    this.history.pop()?.undo();
  }
}

Eine effektive Undo‑Implementierung muss ausreichend Zustand sichern, damit sie die vorherige Situation exakt wiederherstellen kann; ein bloßer zweifacher Aufruf derselben Methode liefert selten das gewünschte Gegenstück, weil die ursprünglichen Daten bereits verändert wurden.

Anwendungsfälle

Commands eignen sich besonders für UI‑Aktionen, die über mehrere Auslöser verfügen, für Makro‑Operationen, Hintergrundwarteschlangen und Audit‑Logs – etwa wenn ein Menüeintrag, ein Toolbar‑Button und ein Tastaturkürzel dieselbe Funktion ausführen sollen.

class MacroCommand implements Command {
  constructor(private commands: Command[]) {}

  execute() {
    for (const command of this.commands) command.execute();
  }

  undo() {
    for (const command of [...this.commands].reverse()) command.undo();
  }
}

Sie lassen sich zudem zur Unterstützung von Rollback‑Abläufen einsetzen. Allerdings erfordern Datenbanktransaktionen und verteilte Kompensationsmechanismen stärkere Garantien, als eine rein im Speicher geführte Command‑Liste bieten kann.

Wann es passt

Für einen einzelnen UI‑Callback genügt häufig eine Closure. Objekt‑Commands hingegen gewinnen an Bedeutung, sobald dieselbe Aktion von verschiedenen Stellen aus ausgelöst wird oder einen eigenständigen Lebenszyklus besitzt, weil sie dann gespeichert, weitergereicht oder später ausgeführt werden können.

Verwandte Muster

Memento bewahrt Zustands‑Snapshots, während Command Aktionen selbst speichert. Composite ermöglicht es, ein Makro aus mehreren Commands zu bilden. Strategy kapselt einen Algorithmus; Command dagegen kapselt eine Anfrage. Diese Muster adressieren unterschiedliche Probleme, lassen sich jedoch kombinieren – beispielsweise kann ein Composite‑Command Memento‑Objekte nutzen, um Zustände wiederherzustellen.

Fazit

Es macht das Command Pattern Aktionen zu Objekten erster Klasse – ein Ansatz, der sich besonders bewährt, sobald eine Anwendung Historien führen, Warteschlangen verwalten, Makros unterstützen oder eine klare Trennung zwischen Auslöser und Implementierung benötigen.

Quellen & Referenzen

  1. [1]
  2. [2]
  3. [3]

Comments (0)

Loading comments...