GoFのデザインパターンをPythonで学習してみたいと思います。
■ Command(コマンド・パターン)
Command パターン(英: command pattern)はオブジェクト指向プログラミングにおけるデザインパターンの一つで、動作を表現するオブジェクトを示す。Command オブジェクトは、動作とそれに伴うパラメータをカプセル化したものである。
例として、印刷を行うライブラリが PrintJob クラスを備えているとする。ライブラリのユーザーは新たに PrintJob オブジェクトを作成し、パラメータ(印刷するドキュメント、印刷部数など)をセットし、最後にプリンターにジョブを送信するメソッドを呼び出す。
UML class and sequence diagram
UML class diagram
■ "Command"のサンプルプログラム
実際に、Commandパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。
- ファイル権限"777"の
test1.txt
ファイルを作成する - ファイル権限"600"の
test2.txt
ファイルを作成する
なお、サンプルプログラムは、第一引数:作成したいファイル名、第二引数:付与したいファイル権限とします。
$ python Main.py test1.txt 777
% touch test1.txt
% chmod 777 test1.txt
$ python Main.py test2.txt 600
% touch test2.txt
% chmod 600 test2.txt
ファイル一覧を確認します。
$ ls -l|grep test
-rwxrwxrwx 1 ttsubo staff 0 1 26 13:01 test1.txt
-rw------- 1 ttsubo staff 0 1 26 13:01 test2.txt
想定どおり、ファイルが生成できました。
■ サンプルプログラムの詳細
Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/Command
- ディレクトリ構成
.
├── Main.py
└── command
└── command.py
(1) Command(命令)の役
命令のインタフェースを定める役です。
サンプルプログラムでは、Command
クラスが、この役を努めます。
from abc import ABCMeta, abstractmethod
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self):
pass
@abstractmethod
def display(self):
pass
(2) ConcreteCommand(具体的命令)の役
Command
役のインタフェースを実際に実装している役です。
サンプルプログラムでは、FileTouchCommand
クラスと ChmodCommand
クラスが、この役を努めます。
class FileTouchCommand(Command):
def __init__(self, filename, receiverObj):
self.__filename = filename
self.__receiver = receiverObj
def execute(self):
self.__receiver.createFile(self.__filename)
def display(self):
print("% touch {0}".format(self.__filename))
class ChmodCommand(Command):
def __init__(self, filename, permission, receiverObj):
self.__filename = filename
self.__permission = permission
self.__receiver = receiverObj
def execute(self):
self.__receiver.changeFileMode(self.__filename, self.__permission)
def display(self):
permission = format(self.__permission, 'o')
print("% chmod {0} {1}".format(permission, self.__filename))
(3) Receiver(受信者)の役
ConcreteCommand
役の命令を実行するときに対象となる役です。命令の受け取り手と呼んでもよいでしょう。
サンプルプログラムでは、FileOperator
クラスが、この役を努めます。
from pathlib import Path
...(snip)
class FileOperator(object):
def createFile(self, filename):
Path(filename).touch()
def changeFileMode(self, filename, permission):
Path(filename).chmod(permission)
(4) Invoker(起動者)の役
命令の実行を開始する役です。Command
役で定義されているインタフェースを呼び出す役になります。
サンプルプログラムでは、CompositeCommand
クラスが、この役を努めます。
class CompositeCommand(Command):
def __init__(self):
self.__cmds = []
def append_cmd(self, cmd):
self.__cmds.append(cmd)
def execute(self):
for cmd in self.__cmds:
cmd.execute()
def display(self):
for cmd in self.__cmds:
cmd.display()
(5) Client(依頼人)の役
ConcreteCommand
役を生成し、その際にReceiver役を割り当てる役です。
サンプルプログラムでは、startMain
メソッドが、この役を努めます。
import sys
from command.command import FileOperator, CompositeCommand, FileTouchCommand, ChmodCommand
def startMain(filename, permission):
recv = FileOperator()
cc = CompositeCommand()
cc.append_cmd(FileTouchCommand(filename, recv))
cc.append_cmd(ChmodCommand(filename, permission, recv))
cc.execute()
cc.display()
if __name__ == "__main__":
startMain(sys.argv[1], int(sys.argv[2], 8))