はじめに
『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
ある日、フォーマットによって出力されるものを変えたいとなった時、
以下のようにフォーマットがhtml
とplain
の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の具象クラスによってオーバーライドできる非抽象メソッドをフックメソッドと呼ぶ。
フックメソッドの使用によって、以下を選択することができる。
- 基底クラスの実装をオーバーライドして別の処理を実行
- 基底クラスの標準実装をそのまま使う
最後に
ひな形をスーパークラスが持っていて、サブクラスでそのひな形を使ったものを作る。
一番最初の一番わかり易いパターンなのだろなと思った。
頭がこんがらがることもなく読み進められた。
本は中古で割りと高かったけどとても役に立ちそうな本だと思った。
デザインパターンはいくつかパラっと見たことはあるものの、よくは知らないのでしっかり勉強しようと思う。
参考
- Rubyによるデザインパターン
- Java言語で学ぶデザインパターン入門