Commandパターン
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 75/91。
Command パターンは、リクエストに関するすべての情報を含む独立したオブジェクトにリクエストを変換する振る舞いに関するデザインパターンです。この変換により、リクエストをメソッドの引数として渡したり、リクエストの実行を遅延またはキューに入れたり、取り消し可能な操作をサポートしたりできます。
レストランを思い浮かべてみてください。
食べ物を注文すると、ウェイターは注文を伝票(command)に書き、それを厨房へ持って行き、シェフが実行します。ウェイターは料理の仕方を知る必要はなく、commandを届けるだけです。
これにより、要求者と実行者が分離されます。
基本的な実装は次のとおりです:
<?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();
}
}
invoker は、commands が何をするのかを知らずに commands を起動します:
<?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));
出力:
Light is ON
Light is OFFCommand Patternは、操作をキューに追加したり、取り消し機能をImplementしたり、アクションをログに記録したりする必要がある場合に特に優れています。各commandは自己完結しているため、既存のコードを変更せずに新しいcommandsを簡単に追加できます。
チャレンジ
簡単Command パターンを使用して、テキストエディターの command システムを構築しましょう。テキストエディターでは、テキストの書き込み、テキストの削除、アクションの取り消しなどの操作をサポートする必要があることがよくあります。それぞれの操作を自己完結型の command オブジェクトにし、統一された interface を通じて実行できるようにします。
コードを4つのファイルに分けて整理します。
Command.php:単一のメソッドexecute(): stringを持つCommandinterface を Define します。これにより、すべてのエディター command が従うべき contract が確立されます。TextEditor.php:receiver、つまり実際に処理を実行するオブジェクトを表すTextEditorclass を Create します。エディターには次の機能を持たせます。- current のテキスト content を保存する(empty 文字列から開始)
- テキストを content に追加し、
"Written: [text]"を返すwrite(string $text): stringメソッドを持つ - content を空にし、
"Content cleared"を返すclear(): stringメソッドを持つ - current の content を返す
getContent(): stringメソッドを持つ
Commands.php:Command ファイルと TextEditor ファイルを Include します。Commandinterface を Implement する2つの command class を Create します。WriteCommand:constructor でTextEditorとテキスト文字列を受け取ります。そのexecute()メソッドはエディターのwrite()メソッドを calls し、その結果を返します。ClearCommand:constructor でTextEditorを受け取ります。そのexecute()メソッドはエディターのclear()メソッドを calls し、その結果を返します。
main.php:Commands ファイルを Include します。2つの入力を受け取ります。command type("write"または"clear")と、テキスト文字列(write command の場合のみ使用)です。TextEditorinstance を Create します。command type Based で、appropriate な command オブジェクトを Create します。次に、command に対してexecute()を calls し、結果を出力する invoker function または単純な仕組みを Create します。新しい行に、エディターの current の content を次の format で出力します:
Content: [content](empty の場合は、スペースの後に何も付けずContent:とだけ出力します)。
この challenge は、Command パターンが各操作をオブジェクトとしてカプセル化する方法を示します。invoker は、write command を実行しているのか clear command を実行しているのかを知る必要がありません。単に execute() を calls し、詳細の処理を command に任せます。
自分で試してみよう
<?php
require_once 'Commands.php';
// 入力を読み取る
$commandType = trim(fgets(STDIN)); // "write" または "clear"
$text = trim(fgets(STDIN)); // writeコマンド用のテキスト
// TODO: TextEditorインスタンスを作成する
// TODO: コマンドタイプに基づいて、適切なコマンドオブジェクトを作成する
// - "write"の場合、エディタとテキストでWriteCommandを作成する
// - "clear"の場合、エディタでClearCommandを作成する
// TODO: コマンドのexecute()を呼び出すインボーカー機構を作成する
// そして結果を出力する
// TODO: エディタの現在のコンテンツを次の形式で出力する: "Content: [content]"
// (空の場合は、スペースの後に何も付けずに "Content: " とだけ出力する)
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1OOPの基礎
外部ファイルOOP入門クラスとオブジェクトの違い$thisキーワードメソッドプロパティコンストラクター(__construct)デストラクター(__destruct)復習 - 簡単な電卓13デザインパターン パート2
CommandパターンAdapterパターンDecoratorパターンTemplate MethodパターンStateパターンCompositeパターンRepositoryパターン自分で練習してみよう: PHPオンラインコンパイラ