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 OFFDas 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.
Aufgabe
EinfachLassen 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 einCommand-Interface mit einer einzigen Methodeexecute(): string. Dies legt den Vertrag fest, dem alle Editor-Befehle folgen müssen.TextEditor.php— Erstellen Sie eineTextEditor-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): stringhaben, die Text an den Inhalt anhängt und"Written: [text]"zurückgibt - Eine Methode
clear(): stringhaben, die den Inhalt leert und"Content cleared"zurückgibt - Eine Methode
getContent(): stringhaben, die den aktuellen Inhalt zurückgibt
Commands.php— Binden Sie die Dateien Command und TextEditor ein. Erstellen Sie zwei Befehlsklassen, die dasCommand-Interface implementieren:WriteCommand— Nimmt einenTextEditorund einen Text-String in seinem Konstruktor entgegen. Seineexecute()-Methode ruft diewrite()-Methode des Editors auf und gibt das Ergebnis zurück.ClearCommand— Nimmt einenTextEditorin seinem Konstruktor entgegen. Seineexecute()-Methode ruft dieclear()-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, derexecute()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 einfachContent: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)
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objekt-Klonen im DetailGeneratoren & Iteratoren13Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterZustandsmusterComposite-MusterRepository-Muster2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung