😊
デザインパターンを学ぶ #12 Command(コマンド)
1. はじめに
今回は Command(コマンド)パターン。
目的は、処理(命令)をオブジェクトとして抽象化し、呼び出し元と実行先を疎結合にすることです。
処理を直接呼ばずに「命令として渡す」ことで、実行の記録・再実行・キュー処理などを柔軟に行えます。
2. Commandとは?
- 命令をオブジェクト化(Command)
- 実行対象(Receiver)への操作をコマンド経由で呼ぶ
- 呼び出し元(Invoker)は中身を知らずに
execute()を実行するだけ
3. 実装イメージ(PHP)
例:ライトのON/OFFを、命令として扱う
<?php
interface Command {
public function execute(): void;
}
// 処理対象(実行者)
class Light {
public function on(): void {
echo "ライトON\n";
}
public function off(): void {
echo "ライトOFF\n";
}
}
// 命令(処理をオブジェクト化)
class LightOnCommand implements Command {
public function __construct(private Light $light) {}
public function execute(): void {
$this->light->on();
}
}
class LightOffCommand implements Command {
public function __construct(private Light $light) {}
public function execute(): void {
$this->light->off();
}
}
// 命令を実行する側
class RemoteControl {
/** @var Command[] */
private array $commands = [];
public function add(Command $command): void {
$this->commands[] = $command;
}
public function run(): void {
foreach ($this->commands as $command) {
$command->execute();
}
}
}
// --- 利用 ---
$light = new Light();
$remote = new RemoteControl();
$remote->add(new LightOnCommand($light));
$remote->add(new LightOffCommand($light));
$remote->run();
出力例:
ライトON
ライトOFF
4. 利用シーン
- 非同期処理やキュー投入(後から実行)
- Undo/Redo の実装
- マクロ(複数命令の一括実行)
- ログ・トランザクションの記録と再実行
5. メリット
- 呼び出し元と実行先を疎結合にできる
- 処理の履歴管理や再実行が可能になる
- 命令を組み合わせたり、蓄積したりできる
6. 注意点
- 命令クラスが増えやすい
- 単純な処理に使うと冗長になる
- Command単体ではUndo処理などは自前実装が必要
7. 他パターンとの比較
| パターン | 違い |
|---|---|
| Strategy | 処理の切り替えに注目(命令の保持はしない) |
| Memento | 状態の保存と復元が目的(Commandは命令そのもの) |
| Observer | 通知が目的(Commandは処理の移譲と記録) |
8. テスト観点
- 複数コマンドを登録 → 順に実行されるか
-
execute()による副作用が正しく起きるか - 同じReceiverでも異なるCommandが独立して動くか
9. まとめ
Commandパターンは、処理をオブジェクト化して切り離す構造パターン。
キュー処理・再実行・複数実行など、**「命令を貯めて実行したい場面」**で役立ちます。
Discussion