3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[デザインパターン学習] Template Methodパターン

Posted at

はじめに

『Rubyによるデザインパターン』という本を買った。
読みながらメモメモ。

変わらないものと変わるものが混ざりに混ざって

もし以下の様なクラスがあったとする。
HTMLでレポートを出力してくれるプログラム。

class Report
	def initialize
		@title = '月次報告'
		@text = ['順調', '最高の調子']
	end

	def output_report
		puts('<html>')
		puts('<head>')
		puts("<title>#{ @title }</title>")
		puts('</head>')
		puts('<body>')
		@text.each do |line|
			puts("<p>#{ line }</p>")
		end
		puts('</body>')
		puts('</html>')
	end
end

report = Report.new
report.output_report

ある日、フォーマットによって出力されるものを変えたいとなった時、
以下のようにフォーマットがhtmlplainの2つに増えただけで分かりにくいプログラムとなる。
もっと他のフォーマットも追加したいなとなった時に更に複雑化する。
間違って正しく動く部分までおかしくしてしまいかねない。

class Report
	def initialize
		@title = '月次報告'
		@text = ['順調', '最高の調子']
	end

	def output_report(format)
		if format == :plain
			puts("*** #{ @title } ***")
		elsif format == :html
			puts('<html>')
			puts('<head>')
			puts("<title>#{ @title }</title>")
			puts('</head>')
			puts('<body>')
		else
			raise "Unknown format #{ format }"
		end
		@text.each do |line|
			if format == :plain
				puts(line)
			else
				puts("<p>#{ line }</p>")
			end
		end
		if format == :html
			puts('</body>')
			puts('</html>')
		end
	end
end

plain = Report.new
plain.output_report(:plain)

html = Report.new
html.output_report(:html)

変わらないものと変わるものを分離

Template Methodパターンは、抽象基底クラスを定義し、テンプレートとなるメソッドを持たせ、基本的な処理の流れを定義する。そして詳細な処理についてはサブクラスに持たせるという方式。

スーパークラスであるReportは処理の流れを持っている。
時にはオーバーライドされない時用の標準実装を持つこともある。

class Report
	def initialize
		@title = '月次報告'
		@text = ['順調', '最高の調子']
	end

	def output_report
		output_start
		output_head
		output_body_start
		output_body
		output_body_end
		output_end
	end

	def output_body
		@text.each do |line|
			output_line(line)
		end
	end

	def output_start
	end

	def output_head
	end

	def output_body_start
	end

	def output_line(line)
	end

	def output_body_end
	end

	def output_end
	end
end

サブクラスでスーパークラスの各メソッドをオーバーライドして、具体的な処理を書く。

class HTMLReport < Report
	def output_start
		puts('<html>')
	end

	def output_head
		puts('<head>')
		puts("<title>#{ @title }</title>")
		puts('</head>')
	end

	def output_body_start
		puts('<body>')
	end

	def output_line(line)
		puts("<p>#{ line }</p>")
	end

	def output_body_end
		puts('</body>')
	end

	def output_end
		puts('</html>')
	end
end
class PlainTextReport < Report
	def output_head
		puts("*** #{ @title } ***")
		puts
	end

	def output_line(line)
		puts(line)
	end
end
html = HTMLReport.new
html.output_report

plain = PlainTextReport.new
plain.output_report

Template Methodの具象クラスによってオーバーライドできる非抽象メソッドをフックメソッドと呼ぶ。

フックメソッドの使用によって、以下を選択することができる。

  1. 基底クラスの実装をオーバーライドして別の処理を実行
  2. 基底クラスの標準実装をそのまま使う

最後に

ひな形をスーパークラスが持っていて、サブクラスでそのひな形を使ったものを作る。
一番最初の一番わかり易いパターンなのだろなと思った。
頭がこんがらがることもなく読み進められた。
本は中古で割りと高かったけどとても役に立ちそうな本だと思った。
デザインパターンはいくつかパラっと見たことはあるものの、よくは知らないのでしっかり勉強しようと思う。

参考

  • Rubyによるデザインパターン
  • Java言語で学ぶデザインパターン入門
3
4
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
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?