読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

命令をクラスにするCommandパターン

デザインパターン Ruby
<スポンサーリンク>

■Commandパターンとは
要求をオブジェクトとしてカプセル化する。
要求を表すオブジェクトや、要求をつっこんだキューやログによって、要求をパラメータとして扱う。
また、取り消し可能なオペレーションをサポートする。

Commandパターンを使うことによって、新しい要求ーーたとえば、ファイルを生成/削除に加えて「コピー」したいという要求ーーが増えても、その新しい要求に対する処理クラスを実装するだけで、既存のクラスを修正することなく対応できるようになる。

f:id:sho322:20140313083817j:plain

■Command.rb
命令を表現する。

class Command
	attr_reader :description

	def initialize(description)
		@description = description
	end

	def execute

	end
end

この「命令」を継承して、executeのメソッドの中身を実装していく。

以下は、具体的な「処理=要求」の実装クラス。クラス図でいうところの、「ConcreteCommand」の部分だ。
■CreateFile.rb

require './Command.rb'

class CreateFile < Command

	def initialize(path, contents)
		super("Create File: #{path}")
		@path = path
		@contents = contents
	end

	def execute
		f = File.open(@path, "w")
		f.write(@contents)
		f.close
	end
end

■DeleteFile.rb

require './Command.rb'

class DeleteFile < Command
	def initialize(path)
		super("Delete File: #{path}")
		@path = path
	end

	def execute
		File.delete(@path)
	end
end

■CopyFile.rb

require './Command.rb'
require 'fileutils'

class CopyFile < Command
	def initialize(source, target)
		super("Copy File:#{source} to #{target}")
		@source = source
		@target = target
	end

	def execute
		FileUtils.copy(@source, @target)
	end
end

■CompositeCommand.rb
これは、複数の命令をまとめた命令を表すクラス。
使う側(=client)はこのクラスを通じて命令を出す。

require './Command.rb'

class CompositeCommand < Command
	def initialize
		@commands = []
	end

	def add_command(cmd)
		@commands << cmd
	end

	def execute
		@commands.each {|cmd| cmd.execute}
	end

	def description
		description = ''
		@commands.each {|cmd| description += cmd.description + "\n"}
		description
	end
end

■client.rb
命令を出してみる。

require './CompositeCommand.rb'
require './CreateFile.rb'
require './CopyFile.rb'
require './DeleteFile.rb'

cmds = CompositeCommand.new

cmds.add_command(CreateFile.new('./file1.txt', "hello world\n"))
cmds.add_command(CopyFile.new('./file1.txt','file2.txt'))
cmds.add_command(DeleteFile.new('./file1.txt'))

puts(cmds.description)
cmds.execute

■Commandパターンのメリット
・既存のコードを修正することなく機能拡張できること
→要求の受付と、要求に対応する処理を切り離して実装できるため。

・クラスの再利用性を向上させること
→命令そのものが独立したクラスとして実装されるため。

■読んだ本

Rubyによるデザインパターン

Rubyによるデザインパターン

この本と、他3冊くらいのデザパタ本を一緒に読みながら練習している。
Rubyデザインパターンを勉強したいときは、この本が一番の選択肢になると思っている。