Design pattern

Command

(Action, Transaction)

Inhaltsverzeichnis

  1. Kerndefinition
  2. Schlechtes Ansatz / Lösung
  3. Grundidee (Prinzip)
  4. Kernkomponenten
  5. Verwendungsbereich
  6. Minecraft-Beispiel
  7. Vorteile & Nachteile
  8. Code-Aufgabe

Was ist das Command Pattern?

Was ist das Command Pattern?

Command ist ein Verhaltensmuster, das eine Anfrage in ein eigenständiges Objekt umwandelt, das alle Informationen über die Anfrage enthält.

Diese Transformation ermöglicht es, Anfragen als Methodenargumente zu übergeben, die Ausführung einer Anfrage zu verzögern oder in eine Warteschlange einzureihen sowie rückgängig zu machende Operationen zu unterstützen.

Schlechtes Ansatz

Schlechtes Ansatz

Command.java


package commands.schlecht;

public interface Command {
    String type();
}
							

Schlechtes Ansatz

CommandExecuter.java


package commands.schlecht;

public class CommandExecuter {

        public void executeCommand(Command command) {
            System.out.println("Executing command: " + command.type());
            switch (command.type()) {
                case "DELETE_TEXT":
                    System.out.println("Deleting text...");
                    break;
                case "INSERT_TEXT":
                    System.out.println("Inserting text...");
                    break;
							 // Immer weiter....
                default:
                    System.out.println("Unknown command type: " + command.type());
            }
        }

        public void undoCommand(Command command) {
            System.out.println("Undoing command: " + command.type());
        }


}
							

Schlechtes Ansatz

DeleteTextCommand.java


package commands.schlecht.text;

import commands.schlecht.Command;

public class DeleteTextCommand implements Command {
    @Override
    public String type() {
        return "DELETE_TEXT";
    }
}
							

Lösung

ist hier

Grundidee (Prinzip)

Grundidee (Prinzip)

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.

Kernkomponenten

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.

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.

Funktionsweise

Funktionsweise

  1. Der Client erstellt den Receiver
  2. Der Client erstellt ein Concrete Command mit dem Receiver
  3. Der Client übergibt das Command an den Invoker
  4. Der Invoker ruft execute() auf
  5. Das Command delegiert die Arbeit an den Receiver

Funktionsweise

Undo / Redo

Ein großer Vorteil des Command Patterns ist die Unterstützung von Undo und Redo.

Undo / Redo

Jede Aktion wird als Command gespeichert

Die Historie wird meist in Stacks verwaltet

Ein Command kann neben execute() auch undo() besitzen

Verwendungsbereich

Verwendungsbereich

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.

Verwendungsbereich

Minecraft

Minecraft

Beziehung zu S-O-L-I-D

S (Single Responsibility):
Jede Klasse hat eine klare Verantwortung — invoker, receiver, command, etc.

O (Open/ Closed):
Neue Befehle können hinzugefügt werden, ohne bestehende Klassen zu verändern.

D (Dependency Inversion):
Aufrufer basieren auf Abstraktionen (Befehl- Schnittstelle) anstatt auf konkreten Klassen.

Vorteile / Nachteile

Vorteile

👍Entkoppelt Sender und Empfänger einer Anfrage.

👍Neue Befehle lassen sich einfach hinzufügen, ohne bestehenden Code zu ändern.

👍Unterstützt Undo/Redo- und Protokollierungsfunktionen.

👍Befehle können zu Makrobefehlen kombiniert werden.

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.

Code-Aufgabe

Es soll eine einfache Fernbedienung implementiert werden, die Folgendes kann:

  1. eine Lampe einschalten
  2. eine Lampe ausschalten
  3. einen Fernseher einschalten
  4. einen Fernseher ausschalten

Wichtige Anforderung: Die Fernbedienung darf nicht wissen, welches Gerät sie steuert. Sie drückt nur Knöpfe.

Zusätzlich: Neue Geräte sollen hinzugefügt werden können, ohne den Code der Fernbedienung zu ändern

Vielen Dank!

Fragen?