Befehlsmuster
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 75 von 91.
Das Command Pattern ist ein Verhaltensentwurfsmuster, das eine Anfrage in ein eigenständiges Objekt umwandelt, das alle Informationen über die Anfrage enthält. Diese Umwandlung ermöglicht es dir, Anfragen als Methodenargumente zu übergeben, die Ausführung einer Anfrage zu verzögern oder in eine Warteschlange zu stellen und rückgängig machbare Vorgänge zu unterstützen.
Stell dir ein Restaurant vor.
Wenn du Essen bestellst, schreibt der Kellner deine Bestellung auf einen Zettel (den Befehl), bringt ihn in die Küche, und der Koch führt ihn aus. Der Kellner muss nicht wissen, wie man kocht; er übermittelt einfach den Befehl.
Dadurch wird der Anforderer vom Ausführer entkoppelt.
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 Aufrufer 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-Muster eignet sich besonders gut, wenn du Vorgänge in eine Warteschlange stellen, eine Rückgängig-Funktion implementieren oder Aktionen protokollieren musst. Jeder Befehl ist in sich geschlossen, sodass du problemlos neue Befehle hinzufügen kannst, ohne vorhandenen Code zu ändern.
Aufgabe
EinfachErstellen wir ein Texteditor-Befehlssystem unter Verwendung des Command Patterns. Texteditoren müssen häufig Vorgänge wie das Schreiben von Text, das Löschen von Text und das Rückgängigmachen von Aktionen unterstützen: Jeder Vorgang wird zu einem eigenständigen Befehlsobjekt, das über eine einheitliche Schnittstelle ausgeführt werden kann.
Du organisierst deinen Code auf vier Dateien verteilt:
Command.php: Definiere eineCommand-Schnittstelle mit einer einzigen Methodeexecute(): string. Dadurch wird der Vertrag festgelegt, den alle Editorbefehle einhalten müssen.TextEditor.php, Erstelle eineTextEditor-Klasse, die den Empfänger darstellt, also das Objekt, das die Arbeit tatsächlich ausführt. Dein Editor sollte:- den aktuellen Textinhalt speichern (beginne mit einer leeren Zeichenkette)
- eine Methode
write(string $text): stringbesitzen, die Text an den Inhalt anhängt und"Written: [text]"zurückgibt - eine Methode
clear(): stringbesitzen, die den Inhalt leert und"Content cleared"zurückgibt - eine Methode
getContent(): stringbesitzen, die den aktuellen Inhalt zurückgibt
Commands.php: Binde die Dateien Command und TextEditor ein. Erstelle zwei Befehlsklassen, die dieCommand-Schnittstelle implementieren:WriteCommand: Nimmt in seinem Konstruktor einenTextEditorund eine Textzeichenkette entgegen. Seine Methodeexecute()ruft die Methodewrite()des Editors auf und gibt das Ergebnis zurück.ClearCommand: Nimmt in seinem Konstruktor einenTextEditorentgegen. Seine Methodeexecute()ruft die Methodeclear()des Editors auf und gibt das Ergebnis zurück.
main.php: Binde die Commands-Datei ein. Du erhältst zwei Eingaben: einen Befehlstyp ("write"oder"clear") und eine Textzeichenkette (wird nur für Schreibbefehle verwendet).Erstelle eine
TextEditor-Instanz. Erstelle abhängig vom Befehlstyp das entsprechende Befehlsobjekt. Erstelle anschließend eine Invoker-Funktion oder einen einfachen Mechanismus, derexecute()für den Befehl aufruft und das Ergebnis ausgibt.Gib in einer neuen Zeile den aktuellen Inhalt des Editors in diesem Format aus:
Content: [content](falls der Inhalt leer ist, gib einfachContent:aus, ohne etwas nach dem Leerzeichen).
Diese Aufgabe zeigt, wie das Command Pattern jeden Vorgang als Objekt kapselt. Der Invoker muss nicht wissen, ob er einen Schreib- oder Löschbefehl ausführt. Er ruft einfach execute() auf und überlässt dem Befehl die Details.
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 write-Befehl
// TODO: Erstelle eine TextEditor-Instanz
// TODO: Basierend auf dem Befehlstyp erstelle das passende 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 aus: "Content: [content]"
// (wenn leer, gib einfach "Content: " aus mit nichts nach dem Leerzeichen)
?>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 OOPKlassen vs. ObjekteDas Schlüsselwort $thisMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDas Schlüsselwort parent::MethodenüberschreibungDas Schlüsselwort finalAbstrakte KlassenRückblick – Mitarbeiterhierarchie7Kapselung
Öffentlich, geschützt, privatZugriffsmodifikatoren im DetailGetter und SetterInformationsverbergungKonstruktor-Promotion (8.0)Wiederholung – System zur Verwaltung von Schülerdatensätzen10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objektklonen im DetailGeneratoren & Iteratoren13Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositummusterRepository-Muster2Namespaces & Autoloading
Einführung in NamespacesDas use-SchlüsselwortPSR-4-Autoloading-StandardComposer-AutoloaderRückblick – Organisiertes Projekt5Schnittstellen & Verträge
Einführung in SchnittstellenSchnittstellen implementierenMehrere Schnittstellen implementierenSchnittstelle vs. abstrakte KlasseTyp-Hinweise mit SchnittstellenRückblick – Formrechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objektklonen__serialize & __unserializeRückblick – Benutzerdefinierte Sammlung11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenBenutzerdefinierte Exception-HierarchieTry, Catch, FinallyRückblick – Formularvalidator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klassen-Eigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenSchreibgeschützte Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphie
Methodenüberschreibung erneut betrachtetPolymorphie über SchnittstellenTyp-Hinweise & Union-TypenSpätes statisches BindenRückblick – Zahlungsabwickler9Traits
Einführung in TraitsMehrere Traits verwendenAuflösung von Trait-KonfliktenAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungÜbe selbstständig: Online-PHP-Compiler