KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

Python基礎 オブジェクト指向22(Command) 振る舞いに関するデザインパターン

登録日 :2026/02/01 15:17
カテゴリ :Python基礎

(オブジェクトの種類)

命令をメソッドではなく、独立したクラスとして表現するパターン

  • 「命令」を送る側と「命令」を受け取る側を分離する
  • 「命令」クラスのインスタンスを切り替えることがでさまざまな処理をすることができる

例)TVのリモコン

構成要素

Command
- 命令を表すインターフェース
- 命令を出すための共通APIを定義

ConcreteCommand
- Commandを実装するクラス
- 具体的な命令を実装
- 内部に命令の受け手となるオブジェクトを保持する。

Invoker
- 命令の送り手となるクラス
- 内部に命令オブジェクトを保持
- 命令を支持する責務を担う

Receiver
- 命令の受取手となるクラス
- 命令をどのように実行するかを知っている
- 任意のクラスがReceiverになることができる

オブジェクト指向的要素

「ポリモーフィズム」を利用したパターン

  • 具体的な「命令」はCommandの子クラスであるConcreteCommandで実装される

  • Invokerは内部にCommand型のオブジェクトを保持し、CommandのAPIを使用することで、ConcreteCommandの追加・削除・切り替えなどが可能になる

メリット・デメリット

メリット

  • 既存のコードを修正することなく、命令の追加・拡張が可能
  • 命令を再利用することができる
  • 処理のキューイングが可能

デメリット

  • 「命令」がシンプルで再利用などを考えなくても良い場合、コードが余計に複雑になる可能性

使い所

  • 複数の命令をひとまとめにして実行したい場合
    命令を再利用して組み合わせることで、一つの命令を生成することが可能

  • 命令をキューに入れて遅延実行したい場合
    命令と実際の実行を別のタイミングで実施することが可能

  • UndoやRedoを実現する

サンプル

例)ファイル操作をキューに入れてまとめて実行する例

from abc import ABC, abstractmethod


class File(object):
    def __init__(self, name: str):
        self.__name = name

    def open(self):
        print(f"{self.__name} is opened")

    def compress(self):
        print(f"{self.__name} is compressed")

    def close(self):
        print(f"{self.__name} is closed")


class Command(ABC):
    @abstractmethod
    def execute(self):
        pass


class OpenCommand(Command):
    def __init__(self, file: File):
        self.__file = file

    def execute(self):
        self.__file.open()


class CompressCommand(Command):
    def __init__(self, file: File):
        self.__file = file

    def execute(self):
        self.__file.compress()


class CloseCommand(Command):
    def __init__(self, file: File):
        self.__file = file

    def execute(self):
        self.__file.close()


class Queue(object):
    def __init__(self):
        self.__commands = []

    def add_command(self, command: Command):
        self.__commands.append(command)

    def execute_command(self):
        for command in self.__commands:
            command.execute()


if __name__ == '__main__':
    file = File("command.py")
    queue = Queue()

    queue.add_command(OpenCommand(file))
    queue.add_command(CompressCommand(file))
    queue.add_command(CloseCommand(file))

    queue.execute_command()