概要
Command(コマンド)パターンは、
操作(命令)をオブジェクトとして抽象化し、呼び出し元と処理内容の結合を分離する構造的パターンである。
これにより、操作のキューイング・履歴管理・Undo/Redo・遅延実行などが柔軟に実現可能になる。
1. なぜCommandパターンが必要か?
❌ 処理ロジックを直接呼び出す密結合な実装
button.onclick = save_file
→ イベント処理や履歴管理、テストが困難で拡張性が乏しい
✅ 操作自体をオブジェクト化し、抽象的に扱う
button.set_command(SaveCommand(file))
→ 操作の呼び出しと実行を切り離し、柔軟な設計が可能に
2. 基本構造
✅ Commandインターフェース
class Command:
def execute(self):
raise NotImplementedError
✅ 具体的なコマンドクラス
class SaveCommand(Command):
def __init__(self, receiver):
self.receiver = receiver
def execute(self):
self.receiver.save()
✅ 受信側(Receiver)
class File:
def save(self):
print("ファイルを保存しました。")
✅ Invoker(呼び出し元)
class Button:
def __init__(self):
self._command = None
def set_command(self, command):
self._command = command
def click(self):
if self._command:
self._command.execute()
✅ 使用例
file = File()
save_cmd = SaveCommand(file)
button = Button()
button.set_command(save_cmd)
button.click()
# → ファイルを保存しました。
3. Python的応用:Undo/Redo対応Commandの設計
class TextEditor:
def __init__(self):
self.content = ""
def write(self, text):
self.content += text
def undo(self, text):
self.content = self.content[:-len(text)]
class WriteCommand(Command):
def __init__(self, editor, text):
self.editor = editor
self.text = text
def execute(self):
self.editor.write(self.text)
def undo(self):
self.editor.undo(self.text)
editor = TextEditor()
history = []
cmd = WriteCommand(editor, "Hello ")
cmd.execute()
history.append(cmd)
cmd2 = WriteCommand(editor, "World!")
cmd2.execute()
history.append(cmd2)
print(editor.content) # Hello World!
# Undo last command
history.pop().undo()
print(editor.content) # Hello
4. 実務ユースケース
✅ UI操作イベントの抽象化
→ ボタンやキーボード操作のイベントを操作オブジェクトとして扱う
✅ 履歴管理・Undo/Redo処理
→ 操作の逆再生を可能にすることで、ユーザー体験を向上
✅ マクロ記録・再実行機能
→ 一連の操作を記録し、自動再生可能に
✅ メッセージキューや非同期処理の設計
→ 遅延実行やリトライ可能なコマンドベースの非同期設計
5. よくある誤用と対策
❌ Commandがただの関数呼び出しラッパーになっている
→ ✅ execute()
に意味ある操作・引数・受信者を含める
❌ Invokerにロジックが集中してしまう
→ ✅ Invokerはコマンドの登録・実行に専念し、処理内容には立ち入らない
❌ Undo処理がCommandの責務外にある
→ ✅ undo()
をCommandに持たせ、処理と巻き戻しを対で設計
結語
Commandパターンとは、“操作そのものをオブジェクト化することで、制御と履歴を手中に収める構造技法”である。
- 処理を呼び出すだけでなく、記録・再生・巻き戻し・遅延実行までを設計可能に
- イベント処理やユーザー操作の抽象化を通じて、拡張性とテスト性の高いアーキテクチャを実現
- Pythonでは第一級関数・動的バインディングを活用して、直感的かつ柔軟にCommandパターンを導入できる
Pythonicとは、“操作をデータとして捉え、再利用と構成を可能にする”ことであり、
Commandパターンはその制御の芸術性を、コードに吹き込むためのデザイン手法である。