概要
Command(コマンド)パターンは、
操作(コマンド)をオブジェクトとして抽象化し、実行、取り消し(Undo)、履歴、バッチ処理などを構造的に制御できるようにするデザインパターンである。
操作の実行者と実装を分離することで、柔軟な処理制御・操作の記録・非同期実行などに対応可能。
1. なぜCommandが必要か?
❌ 呼び出し元が処理内容とその制御すべてを抱え込んでしまう
def execute():
save()
undo_stack.append("save")
→ 操作の記録・再実行・Undoが煩雑になり、拡張性が低下
✅ 操作自体をオブジェクト化し、履歴管理や制御の仕組みに統合
cmd = SaveCommand(editor)
invoker.execute(cmd)
→ すべての操作をオブジェクトで統一的に管理可能
2. 基本構造
✅ Commandインターフェース
class Command:
def execute(self):
raise NotImplementedError
def undo(self):
raise NotImplementedError
✅ Receiver(処理対象)
class Editor:
def __init__(self):
self.content = ""
def write(self, text):
self.content += text
print(f"書き込み: {text} 現在: {self.content}")
def delete_last(self):
removed = self.content[-1]
self.content = self.content[:-1]
print(f"削除: {removed} 現在: {self.content}")
✅ ConcreteCommand(操作の具象クラス)
class WriteCommand(Command):
def __init__(self, editor: Editor, text: str):
self.editor = editor
self.text = text
def execute(self):
self.editor.write(self.text)
def undo(self):
for _ in self.text:
self.editor.delete_last()
✅ Invoker(操作の発行と履歴管理)
class CommandInvoker:
def __init__(self):
self.history = []
def execute(self, command: Command):
command.execute()
self.history.append(command)
def undo(self):
if self.history:
cmd = self.history.pop()
cmd.undo()
✅ 使用例
editor = Editor()
invoker = CommandInvoker()
cmd1 = WriteCommand(editor, "Hi")
cmd2 = WriteCommand(editor, "!")
invoker.execute(cmd1)
invoker.execute(cmd2)
invoker.undo() # 「!」を削除
invoker.undo() # 「Hi」を削除
出力:
書き込み: Hi 現在: Hi
書き込み: ! 現在: Hi!
削除: ! 現在: Hi
削除: i 現在: H
削除: H 現在:
3. Python的応用:ラムダ関数での簡易コマンドパターン
class LambdaCommand(Command):
def __init__(self, do, undo):
self._do = do
self._undo = undo
def execute(self):
self._do()
def undo(self):
self._undo()
→ 軽量な処理ならラムダで即座にCommand化可能
4. 実務ユースケース
✅ テキストエディタのUndo/Redo処理
→ 操作の記録と巻き戻しをCommandで管理
✅ GUIボタンアクションのカプセル化
→ ボタンにCommandをバインドすることで動的制御が可能
✅ スケジューラや非同期処理のキューイング
→ 各操作をCommandとして扱うことで順次実行・並列処理が容易に
✅ マクロ・バッチ処理
→ 複数のCommandを順にまとめて実行可能
5. よくある誤用と対策
❌ Commandが受け取り手(Receiver)に過度に依存
→ ✅ Commandは受け取り手を隠蔽しつつ、責務を限定的に持つ
❌ InvokerがCommandの中身に干渉してしまう
→ ✅ InvokerはCommandの実行とUndo呼び出しだけを担う
❌ Commandを設計せず、ただの関数呼び出しに留める
→ ✅ 「操作をオブジェクト化する」ことがこのパターンの要点
結語
Commandパターンとは、“操作という振る舞いをオブジェクトとして制御する設計”である。
- 実行・取り消し・履歴管理といった処理制御を、構造的かつ拡張可能に管理
- 操作の抽象化により、UI・非同期・マクロ・バッチ処理との統合が容易
- Pythonでは関数/ラムダ/クラスを柔軟に使い分け、Commandの表現力を自在に操れる
Pythonicとは、“動作をデータとして管理すること”。
Commandパターンはその操作の知性を、設計の記録性と制御性に変換する技法である。