🧩 Command パターン
✅ 設計意図
- 各操作を「命令オブジェクト」として抽象化し、履歴として保存
- 実行 (
execute()
)、取り消し (undo()
)、再実行が可能
✅ 適用理由
- 操作の履歴管理、Undo/Redo の実装に最適
- 操作単位の記録が可能で、テストやログ出力にも応用可
✅ 向いているシーン
- テキストエディタ、フォーム、バッチ処理、GUI 操作 など
- 「操作」と「結果」を分離して管理したい場面
✅ コード例
- TypeScript
- PHP
- Python
// コマンドインターフェース
interface Command {
execute(): void;
undo(): void;
}
// 受信者(対象クラス)
class TextEditor {
private content = "";
add(text: string) {
this.content += text;
}
remove(length: number) {
this.content = this.content.slice(0, -length);
}
getContent(): string {
return this.content;
}
}
// コマンド実装
class TypeCommand implements Command {
constructor(private editor: TextEditor, private text: string) {}
execute(): void {
this.editor.add(this.text);
}
undo(): void {
this.editor.remove(this.text.length);
}
}
// 利用例
const editor = new TextEditor();
const history: Command[] = [];
const cmd1 = new TypeCommand(editor, "Hello ");
cmd1.execute();
history.push(cmd1);
const cmd2 = new TypeCommand(editor, "World");
cmd2.execute();
history.push(cmd2);
console.log(editor.getContent()); // Hello World
// Undo(巻き戻し)
const last = history.pop();
last?.undo();
console.log(editor.getContent()); // Hello
<?php
interface Command {
public function execute(): void;
public function undo(): void;
}
class TextEditor {
private string $content = "";
public function add(string $text): void {
$this->content .= $text;
}
public function remove(int $length): void {
$this->content = substr($this->content, 0, -$length);
}
public function getContent(): string {
return $this->content;
}
}
class TypeCommand implements Command {
public function __construct(private TextEditor $editor, private string $text) {}
public function execute(): void {
$this->editor->add($this->text);
}
public function undo(): void {
$this->editor->remove(strlen($this->text));
}
}
// 利用例
$editor = new TextEditor();
$history = [];
$cmd1 = new TypeCommand($editor, "Hello ");
$cmd1->execute();
$history[] = $cmd1;
$cmd2 = new TypeCommand($editor, "World");
$cmd2->execute();
$history[] = $cmd2;
echo $editor->getContent() . "\n"; // Hello World
// Undo
$last = array_pop($history);
$last->undo();
echo $editor->getContent() . "\n"; // Hello
from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self): pass
@abstractmethod
def undo(self): pass
class TextEditor:
def __init__(self):
self.content = ""
def add(self, text: str):
self.content += text
def remove(self, length: int):
self.content = self.content[:-length]
def get_content(self) -> str:
return self.content
class TypeCommand(Command):
def __init__(self, editor: TextEditor, text: str):
self.editor = editor
self.text = text
def execute(self):
self.editor.add(self.text)
def undo(self):
self.editor.remove(len(self.text))
# 利用例
editor = TextEditor()
history: list[Command] = []
cmd1 = TypeCommand(editor, "Hello ")
cmd1.execute()
history.append(cmd1)
cmd2 = TypeCommand(editor, "World")
cmd2.execute()
history.append(cmd2)
print(editor.get_content()) # Hello World
# Undo
last = history.pop()
last.undo()
print(editor.get_content()) # Hello
✅ 解説
このコードは Command
パターン を使用して、操作(コマンド)をオブジェクトとしてカプセル化し、
操作の実行や取り消し(Undo
)を可能にする設計を実現している。Command
パターンは、操作をオブジェクトとして表現し、
操作の履歴管理や取り消しを容易にするデザインパターン。
1. Command パターンの概要
- Command: 操作を表現するインターフェース
- このコードでは
Command
が該当
- このコードでは
- ConcreteCommand:
Command
を実装し、具体的な操作を定義するクラス- このコードでは
TypeCommand
が該当
- このコードでは
- Receiver: 実際の操作を実行するクラス
- このコードでは
TextEditor
が該当
- このコードでは
- Invoker:
Command
を実行する役割を持つクラス(またはコード)- このコードでは
history
配列を利用してコマンドを管理
- このコードでは
2. 主なクラスとその役割
Command
- 操作の共通インターフェース
execute
メソッドで操作を実行undo
メソッドで操作を取り消し
TypeCommand
Command
を実装した具体的なコマンドクラスexecute
メソッドでテキストを追加undo
メソッドで追加したテキストを削除
TextEditor
- 受信者(
Receiver
) - テキストの追加や削除を実行し、現在の内容を保持
- 受信者(
- クライアントコード
TypeCommand
を生成し、execute
メソッドを呼び出して操作を実行history
配列でコマンドの履歴を管理し、undo
メソッドで操作を取り消し
3. UML クラス図
4. Command パターンの利点
- 操作のカプセル化: 操作をオブジェクトとして表現することで、操作の履歴管理や取り消しが容易になる
- 柔軟性: 新しい操作を追加する場合も、
Command
を実装するだけで対応可能 - 履歴管理: 操作の履歴を保存し、
Undo/Redo
機能を実現可能
この設計は、操作の履歴管理や取り消しが必要な場面で非常に有効であり、コードの柔軟性と保守性を向上させる。