2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するCommandパターン:操作をオブジェクト化して履歴と再実行を設計する

Posted at

概要

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パターンはその制御の芸術性を、コードに吹き込むためのデザイン手法である。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?