GoFのデザインパターン(Design Pattern)のコマンド(Command)のRubyコードを使った紹介記事です。
コマンドデザインパターンは、あるオブジェクトに対してコマンドを送ることでそのオブジェクトのメソッドを呼び出すことです。
たとえば、ファイルシステムの実装は知らなくてもユーザーはファイルの追加、削除といったコマンドを実行できます。これもコマンドパターンのひとつです。
🍮コマンドの構成要素
コマンドの構成要素は、シンプルに2つです。
- Command(コマンド):コマンドのインターフェイス
- ConcreteCommand(具体コマンド):Commandの具体的な処理
🍣コマンドのメリット
🎳ソースコード
コマンドデザインパターンを説明するために、ファイルの作成・削除・コピーができるモデルを考えます。
- Commandクラス:すべてのCommandのインターフェイス
- CreateFileクラス(ConcreteCommand):ファイルを作成する
- DeleteFileクラス(ConcreteCommand):ファイルを削除する
- CopyFileクラス(ConcreteCommand):ファイルをコピーする
- CompositeCommand(ConcreteCommand):複数のコマンドをまとめて実行できるようにした、CreateFile, DeleteFile, CopyFileのコマンドを集約するクラス
まず、すべてのコマンドのインタフェースを規定するCommandクラスです。
このクラスで定義した#executeメソッドと#undo_executeメソッドをCreateFile, DeleteFile, CopyFileが持っています。
# コマンドのインターフェース classCommand attr_reader:description definitialize(description) @description = description end
defexecute end
defundo_execute end end
|
次にCreateFileクラス,DeleteFileクラス,CopyFileクラスです。各クラスの共通した特徴は次のとおりです。
- 各クラスは
Commandクラスを継承したConcreteCommand #executeメソッド:ファイル作成、ファイル削除、ファイルコピーを実装#undo_executeメソッド:ファイル作成、ファイル削除、ファイルコピーを取り消す
なお、最初にrequireしているfileutilsは、ファイルを操作するためのライブラリです。
require"fileutils"
# ファイルを作成する命令 classCreateFile< Command definitialize(path, contents) super("Create file :#{path}") @path = path @contents = contents end
defexecute f = File.open(@path,"w") f.write(@contents) f.close end
defundo_execute File.delete(@path) end end
# ファイルを削除する命令 classDeleteFile< Command definitialize(path) super("Delete file :#{path}") @path = path end
defexecute if File.exists?(@path) @content = File.read(@path) end File.delete(@path) end
defundo_execute f = File.open(@path,"w") f.write(@contents) f.close end end
# ファイルをコピーする命令 classCopyFile< Command definitialize(source, target) super("Copy file :#{source} to#{target}") @source = source @target = target end
defexecute FileUtils.copy(@source, @target) end
defundo_execute File.delete(@target) if(@contents) f = File.open(@target,"w") f.write(@contents) f.close end end end
|
最後にCreateFileクラス,DeleteFileクラス,CopyFileクラスを組み合わせて実行できるようにしたCompositeCommandクラスです。このクラスもCommandを継承している、ConcreteCommandのひとつです。
# 複数のコマンドをまとめて実行できるようにしたオブジェクト classCompositeCommand< Command definitialize @commands = [] end
defadd_command(cmd) @commands<< cmd end
defexecute @commands.each {|cmd| cmd.execute } end
defundo_execute @commands.reverse.each {|cmd| cmd.undo_execute } end
defdescription description ="" @commands.each {|cmd| description += cmd.description +"\n"} description end end
|
コーディングは以上です。実際に動かしてみます。
command_list = CompositeCommand.new command_list.add_command(CreateFile.new("file1.txt","hello world\n")) command_list.add_command(CopyFile.new("file1.txt","file2.txt")) command_list.add_command(DeleteFile.new("file1.txt"))
command_list.execute puts(command_list.description) #=> Create file : file1.txt #=> Copy file : file1.txt to file2.txt #=> Delete file : file1.txt
# 処理を取り消すコマンド command_list.undo_execute #=> file2が消えている
|
このように使う側はCommandの本当の実装は知りませんが、ファイルの作成、ファイルのコピー、ファイルの削除のコマンドを実行できました。
🚕サンプルソース
🐡参考リンク
🖥 VULTRおすすめ
「VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!