第3章 アルゴリズムを変更する: Template Method
Ruby
Published: 2019-06-18

「Rubyによるデザインパターン」の読書メモです。

時々、個人の見解入りです。

修正前

例えば下記のようなコードがあったとします。

ここから、htmlではなくプレーンテキスト形式でもレポートを表示する要件が加わったとき、どうすれば良いでしょうか。

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

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

Report.new.output_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

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

  def output_start
  end

  def output_head
    output_line(@title)
    puts
  end

  def output_body_start
  end

  def output_line(line)
    raise "Called abstract method: #{__method__}"
  end

  def output_body_end
  end

  def output_end
  end
end

class HTMLReport < Report

private
  def output_start
    puts '<html>'
  end

  def output_head
    puts "<head><title>#{@title}</title></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

private
  def output_line(line)
    puts(line)
  end
end


p '-- HTMLReport --'
HTMLReport.new.output_report

p '-- PlainTextReport --'
PlainTextReport.new.output_report

これで新しいフォーマットが必要になった場合も、サブクラス追加で出来ますね。

※ 本のサンプルコードに少し手を加えています。

おまけ

ダックタイピング

「もしアヒルのように見えて、アヒルのように鳴くのなら、それはアヒルである」

注意点

すべての起こりうる事態に対処するために、サブクラスに大量のメソッドをオーバーライドさせるようなテンプレートクラスを作成するのは避けましょう。