Menu
Coddy logo textTech

Command-Muster

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 75 von 91.

Das Command-Muster (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.

Denken Sie an ein Restaurant.

Wenn Sie Essen bestellen, schreibt der Kellner Ihre Bestellung auf einen Zettel (den Befehl), bringt diesen in die Küche und der Koch führt ihn aus. Der Kellner muss nicht wissen, wie man kocht; er überbringt lediglich den Befehl.

Dies entkoppelt den Anforderer vom Ausführer.

Hier ist eine grundlegende Implementierung:

<?php
interface Command {
    public function execute(): string;
}
class Light {
    public function on(): string { return "Light is ON"; }
    public function off(): string { return "Light is OFF"; }
}
class LightOnCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->on();
    }
}
class LightOffCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->off();
    }
}

Der Invoker löst Befehle aus, ohne zu wissen, was sie tun:

<?php
class RemoteControl {
    public function press(Command $command): string {
        return $command->execute();
    }
}
$light = new Light();
$remote = new RemoteControl();

echo $remote->press(new LightOnCommand($light)) . "\n";
echo $remote->press(new LightOffCommand($light));

Ausgabe:

Light is ON
Light is OFF

Das Command-Pattern zeichnet sich dadurch aus, wenn Sie Operationen in eine Warteschlange stellen, eine Rückgängig-Funktionalität implementieren oder Aktionen protokollieren müssen. Jeder Befehl ist in sich abgeschlossen, was es einfach macht, neue Befehle hinzuzufügen, ohne bestehenden Code zu ändern.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Texteditor-Befehlssystem mit dem Command Pattern erstellen. Texteditoren müssen oft Operationen wie das Schreiben von Text, das Löschen von Text und das Rückgängigmachen von Aktionen unterstützen — jede Operation wird zu einem eigenständigen Befehlsobjekt, das über eine einheitliche Schnittstelle ausgeführt werden kann.

Sie werden Ihren Code über vier Dateien organisieren:

  • Command.php — Definieren Sie ein Command-Interface mit einer einzigen Methode execute(): string. Dies legt den Vertrag fest, dem alle Editor-Befehle folgen müssen.
  • TextEditor.php — Erstellen Sie eine TextEditor-Klasse, die den Empfänger (Receiver) darstellt — das Objekt, das die eigentliche Arbeit verrichtet. Ihr Editor sollte:
    • Den aktuellen Textinhalt speichern (beginnen Sie mit einem leeren String)
    • Eine Methode write(string $text): string haben, die Text an den Inhalt anhängt und "Written: [text]" zurückgibt
    • Eine Methode clear(): string haben, die den Inhalt leert und "Content cleared" zurückgibt
    • Eine Methode getContent(): string haben, die den aktuellen Inhalt zurückgibt
  • Commands.php — Binden Sie die Dateien Command und TextEditor ein. Erstellen Sie zwei Befehlsklassen, die das Command-Interface implementieren:
    • WriteCommand — Nimmt einen TextEditor und einen Text-String in seinem Konstruktor entgegen. Seine execute()-Methode ruft die write()-Methode des Editors auf und gibt das Ergebnis zurück.
    • ClearCommand — Nimmt einen TextEditor in seinem Konstruktor entgegen. Seine execute()-Methode ruft die clear()-Methode des Editors auf und gibt das Ergebnis zurück.
  • main.php — Binden Sie die Datei Commands ein. Sie erhalten zwei Eingaben: einen Befehlstyp ("write" oder "clear") und einen Text-String (der nur für Schreibbefehle verwendet wird).

    Erstellen Sie eine TextEditor-Instanz. Erstellen Sie basierend auf dem Befehlstyp das entsprechende Befehlsobjekt. Erstellen Sie dann eine Invoker-Funktion oder einen einfachen Mechanismus, der execute() auf dem Befehl aufruft und das Ergebnis ausgibt.

    Geben Sie in einer neuen Zeile den aktuellen Inhalt des Editors in diesem Format aus: Content: [content] (wenn er leer ist, geben Sie einfach Content: ohne etwas nach dem Leerzeichen aus).

Diese Herausforderung zeigt, wie das Command Pattern jede Operation als Objekt kapselt. Der Aufrufer (Invoker) muss nicht wissen, ob er einen Schreib- oder Löschbefehl ausführt — er ruft einfach execute() auf und lässt den Befehl die Details handhaben.

Spickzettel

Das Command-Pattern (Befehlsmuster) ist ein Verhaltensentwurfsmuster, das eine Anfrage als eigenständiges Objekt kapselt, welches alle Informationen über die Anfrage enthält. Dies ermöglicht es Ihnen, Anfragen als Methodenargumente zu übergeben, Operationen in eine Warteschlange zu stellen und rückgängig machbare Aktionen zu unterstützen.

Das Muster entkoppelt den Anforderer (Invoker) vom Ausführenden (Receiver), ähnlich wie ein Kellner Bestellungen an einen Koch überbringt, ohne wissen zu müssen, wie man kocht.

Grundstruktur

Definieren Sie ein Command-Interface mit einer execute()-Methode:

interface Command {
    public function execute(): string;
}

Erstellen Sie eine Receiver-Klasse, die die eigentliche Arbeit verrichtet:

class Light {
    public function on(): string { return "Light is ON"; }
    public function off(): string { return "Light is OFF"; }
}

Implementieren Sie konkrete Befehlsklassen, die spezifische Aktionen kapseln:

class LightOnCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->on();
    }
}

class LightOffCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->off();
    }
}

Invoker

Der Invoker (Aufrufer) löst Befehle aus, ohne deren Implementierungsdetails zu kennen:

class RemoteControl {
    public function press(Command $command): string {
        return $command->execute();
    }
}

$light = new Light();
$remote = new RemoteControl();

echo $remote->press(new LightOnCommand($light)) . "\n";
echo $remote->press(new LightOffCommand($light));

Vorteile

Das Command-Pattern ist ideal für das Warteschlangenmanagement von Operationen, die Implementierung von Rückgängig-Funktionen oder das Protokollieren von Aktionen. Jeder Befehl ist in sich abgeschlossen, was es einfach macht, neue Befehle hinzuzufügen, ohne bestehenden Code zu ändern.

Probier es selbst

<?php

require_once 'Commands.php';

// Eingabe lesen
$commandType = trim(fgets(STDIN)); // "write" oder "clear"
$text = trim(fgets(STDIN));         // Text für den Schreibbefehl

// TODO: Erstelle eine TextEditor-Instanz

// TODO: Erstelle basierend auf dem Befehlstyp das entsprechende Befehlsobjekt
// - Wenn "write", erstelle einen WriteCommand mit dem Editor und dem Text
// - Wenn "clear", erstelle einen ClearCommand mit dem Editor

// TODO: Erstelle einen Invoker-Mechanismus, der execute() auf dem Befehl aufruft
// und das Ergebnis ausgibt

// TODO: Gib den aktuellen Inhalt des Editors im Format "Content: [content]" aus
// (wenn leer, gib einfach "Content: " ohne etwas nach dem Leerzeichen aus)

?>
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