Menu
Coddy logo textTech

Command-Muster

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 70 von 87.

Das Command Pattern 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 Ihnen, Anfragen als Methodenargumente zu übergeben, die Ausführung einer Anfrage zu verzögern oder in eine Warteschlange zu stellen und rückgängig machbare Operationen zu unterstützen.

Stellen Sie es sich wie ein Restaurant vor: Anstatt dem Koch direkt zu sagen, was er kochen soll, schreiben Sie Ihre Bestellung auf einen Zettel. Der Kellner (Invoker) bringt den Zettel (Command) in die Küche, wo er in eine Warteschlange eingereiht, priorisiert oder sogar storniert werden kann. Das Muster entkoppelt das Objekt, das die Operation aufruft, von demjenigen, das sie ausführt.

Das Muster besteht aus vier Schlüsselkomponenten: einem Command-Interface, das die execute-Methode deklariert, ConcreteCommand-Klassen, die spezifische Aktionen implementieren, einem Receiver, der die eigentliche Arbeit verrichtet, und einem Invoker, der Befehle auslöst:

interface Command {
    void execute();
}
class Light {  // Empfänger
    public void turnOn() {
        System.out.println("Light is ON");
    }
    public void turnOff() {
        System.out.println("Light is OFF");
    }
}
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
}
class RemoteControl {  // Aufrufer (Invoker)
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

Der Invoker weiß nicht, welche Aktion ausgeführt wird – er ruft lediglich execute() auf:

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // Ausgabe: Licht ist AN

Das Command-Pattern zeichnet sich aus, wenn Sie Operationen in eine Warteschlange stellen, eine Undo/Redo-Funktionalität implementieren oder Aufgaben für eine spätere Ausführung planen müssen. Jedes Command kapselt alles Notwendige, um eine Aktion auszuführen, was Ihr System flexibler und erweiterbarer macht.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Smart-Home-Automatisierungssystem mit dem Command Pattern bauen! Sie erstellen ein System, in dem verschiedene Heimgeräte über Befehle gesteuert werden können, was es ermöglicht, Aktionen in eine Warteschlange zu stellen, auszuführen und sogar für die spätere Verwendung zu speichern – genau wie eine Universalfernbedienung, die nicht wissen muss, wie jedes Gerät intern funktioniert.

Sie werden Ihren Code über vier Dateien organisieren:

  • Command.java: Definieren Sie das Command-Interface, das alle Gerätebefehle implementieren werden. Es sollte eine einzige Methode execute() deklarieren, die die Aktion des Befehls ausführt.
  • Devices.java: Erstellen Sie zwei Receiver-Klassen, die Smart-Home-Geräte repräsentieren:

    Television - hat die Methoden powerOn(), die TV is now ON ausgibt, powerOff(), die TV is now OFF ausgibt, und setChannel(int channel), die TV channel set to [channel] ausgibt.

    Thermostat - hat die Methoden setTemperature(int temp), die Thermostat set to [temp] degrees ausgibt, und turnOff(), die Thermostat turned OFF ausgibt.

  • Commands.java: Erstellen Sie konkrete Befehlsklassen, die die Geräteoperationen kapseln:

    TVOnCommand - nimmt ein Television-Objekt in seinem Konstruktor entgegen und ruft bei der Ausführung powerOn() auf.

    TVOffCommand - nimmt ein Television-Objekt in seinem Konstruktor entgegen und ruft bei der Ausführung powerOff() auf.

    TVChannelCommand - nimmt ein Television-Objekt und ein int channel in seinem Konstruktor entgegen und ruft bei der Ausführung setChannel() mit diesem Kanal auf.

    ThermostatSetCommand - nimmt ein Thermostat-Objekt und ein int temperature in seinem Konstruktor entgegen und ruft bei der Ausführung setTemperature() mit diesem Wert auf.

  • Main.java: Erstellen Sie eine RemoteControl-Klasse (den Invoker), die eine Methode setCommand(Command cmd) zum Speichern eines Befehls und pressButton() zum Ausführen des gespeicherten Befehls hat.

    In Ihrer Main-Methode erhalten Sie zwei Eingaben: eine TV-Kanalnummer (Integer) und eine Thermostattemperatur (Integer).

    Erstellen Sie ein Television-Objekt und ein Thermostat-Objekt. Erstellen Sie eine RemoteControl und demonstrieren Sie das Command Pattern durch:

    1. Setzen eines TVOnCommand und Drücken der Taste
    2. Setzen eines TVChannelCommand mit Ihrem eingegebenen Kanal und Drücken der Taste
    3. Setzen eines ThermostatSetCommand mit Ihrer eingegebenen Temperatur und Drücken der Taste
    4. Setzen eines TVOffCommand und Drücken der Taste

Sie erhalten zwei Eingaben in dieser Reihenfolge: den TV-Kanal (Integer) und die Thermostattemperatur (Integer).

Zum Beispiel wäre bei den Eingaben 5 und 72 Ihre Ausgabe:

TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF

Beachten Sie, dass die RemoteControl nie direkt mit den Geräten interagiert – sie kennt nur das Command-Interface. Jeder Befehl kapselt alles, was zur Ausführung seiner Aktion erforderlich ist, was es einfach macht, neue Geräte und Befehle hinzuzufügen, ohne den Invoker zu ändern!

Spickzettel

Das Command-Muster ist ein Verhaltensmuster, das eine Anfrage als Objekt kapselt. Dies ermöglicht es, Clients mit verschiedenen Anfragen zu parametrisieren, Anfragen in Warteschlangen zu stellen oder zu protokollieren und rückgängig machbare Operationen zu unterstützen.

Das Muster entkoppelt das Objekt, das die Operation aufruft (Invoker), von demjenigen, das sie ausführt (Receiver).

Kernkomponenten

  • Command: Interface, das die Methode execute() deklariert
  • ConcreteCommand: Klassen, die spezifische Aktionen implementieren
  • Receiver: Objekt, das die eigentliche Arbeit verrichtet
  • Invoker: Objekt, das Befehle auslöst

Grundstruktur

// Command-Interface
interface Command {
    void execute();
}

// Receiver
class Light {
    public void turnOn() {
        System.out.println("Light is ON");
    }
    public void turnOff() {
        System.out.println("Light is OFF");
    }
}

// ConcreteCommand
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
}

// Invoker
class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

Verwendung

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // Ausgabe: Light is ON

Der Invoker weiß nicht, welche Aktion ausgeführt wird – er ruft lediglich execute() auf. Dies macht das System flexibel und erweiterbar, ideal für das Warteschlangenmanagement von Operationen, die Implementierung von Rückgängig/Wiederholen-Funktionalitäten oder die Planung von Aufgaben.

Probier es selbst

import java.util.Scanner;

// TODO: Erstelle die Klasse RemoteControl (den Invoker) mit:
// - der Methode setCommand(Command cmd), um einen Befehl zu speichern
// - der Methode pressButton(), um den gespeicherten Befehl auszuführen

class RemoteControl {
    // TODO: Implementiere RemoteControl
}

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Eingaben lesen
        int channel = scanner.nextInt();
        int temperature = scanner.nextInt();
        
        // TODO: Erstelle einen Television und einen Thermostat
        
        // TODO: Erstelle eine RemoteControl
        
        // TODO: Demonstriere das Command Pattern:
        // 1. Setze einen TVOnCommand und drücke den Knopf
        // 2. Setze einen TVChannelCommand mit dem eingegebenen Kanal und drücke den Knopf
        // 3. Setze einen ThermostatSetCommand mit der eingegebenen Temperatur und drücke den Knopf
        // 4. Setze einen TVOffCommand und drücke den Knopf
        
        scanner.close();
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung