概要
Command(コマンド)パターンは、
操作そのものをオブジェクトとして抽象化し、再実行・取り消し・キュー処理などを可能にする設計パターンである。
ボタン1つで複数の操作を実行したり、ユーザー操作をログに記録してUndoできるようにしたり、“実行”を第一級オブジェクトとして扱う柔軟性を設計にもたらす。
1. なぜCommandが必要か?
❌ 処理が固定されていて、変更・再利用が困難になる
def on_button_click():
print("保存中…")
save_data()
log_action()
→ ボタンやイベントが実行する操作がハードコードされており、拡張性に乏しい
✅ 操作(コマンド)をオブジェクト化し、呼び出し元から分離する
button.set_command(SaveCommand())
button.click()
→ コマンドの差し替え・記録・Undoなどが自在に行える
2. 基本構造
✅ Commandインターフェース
class Command:
def execute(self):
raise NotImplementedError
✅ ConcreteCommand(具体的な処理)
class SaveCommand(Command):
def execute(self):
print("保存処理を実行")
class LoadCommand(Command):
def execute(self):
print("読み込み処理を実行")
✅ Invoker(コマンドを保持し実行する存在)
class Button:
def __init__(self):
self._command = None
def set_command(self, command: Command):
self._command = command
def click(self):
if self._command:
self._command.execute()
✅ 使用例
button = Button()
button.set_command(SaveCommand())
button.click()
button.set_command(LoadCommand())
button.click()
出力:
保存処理を実行
読み込み処理を実行
3. Python的応用:ラムダ式や関数をCommandのように扱う
class FunctionalButton:
def __init__(self):
self._handler = None
def set_action(self, fn):
self._handler = fn
def click(self):
if self._handler:
self._handler()
button = FunctionalButton()
button.set_action(lambda: print("PDFを生成"))
button.click()
→ 関数やクロージャを使って簡易Commandとして機能させることも可能
4. 実務ユースケース
✅ Undo / Redo 機能
→ 実行されたコマンドを履歴に残すことで状態の巻き戻しが可能
✅ マクロ・バッチ処理の記録と再実行
→ コマンドのシーケンスを記録し、まとめて再適用
✅ UIボタンやキーボードショートカットの操作切り替え
→ 操作の動作を外部から柔軟に切り替えられる
✅ タスクスケジューラやジョブキュー
→ 処理内容をコマンドとしてキューに登録し順次実行
5. よくある誤用と対策
❌ 単なる関数呼び出しのラッパーに留まり、オブジェクト化の恩恵を活かしていない
→ ✅ 実行に加えて、Undo・Redo・ログ・メタ情報の付加を視野に設計
❌ Invoker がコマンドの中身を知ってしまっている
→ ✅ Invoker は execute()
を呼び出すだけに留める
❌ コマンドが巨大化して責務過多に
→ ✅ 責務分離し、1つのコマンドには1つの操作原則を守らせる
結語
Commandパターンとは、“操作をデータとして持ち運び、設計に再実行性と可逆性を与える構造”である。
- 処理を抽象化し、呼び出し元と実行内容を分離することで柔軟なアクション制御が可能
- Undo / Redo、マクロ、バッチなど、実行履歴の記録・操作が容易になる
- Pythonではオブジェクト・クロージャ・ラムダ式でCommand的構造をシンプルに表現可能
Pythonicとは、“操作を命令としてではなく、データとして捉えること”。
Commandパターンはその動作の知性を、構造と制御に転化する技法である。