Design Patterns in Ruby [Digest 2] - Template

When we have a complex algorithm including several steps to build something, which would be vary in the middle.
Now you need Template method.

It comes up with an example:

class Report
  def initialize
    @title = 'Monthly Report'
    @text = [ 'Things are going', 'really, really well.' ]
  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

 

The usage of the class is as below:

report = Report.new
report.output_report

 

When they need something more? It will support plain text or RTF or PostScript.

The code will mess up with many if ... elsif ... else conditions

So, let's do the seperate thing:
Separate the Things That Stay the Same

class Report
  def initialize
    @title = 'Monthly Report'
    @text = ['Things are going', 'really, really well.']
  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
    raise 'Called abstract method: output_start'
  end
  def output_head
    raise 'Called abstract method: output_head'
  end
  
  def output_body_start
    raise 'Called abstract method: output_body_start'
  end
  def output_line(line)
    raise 'Called abstract method: output_line'
  end
  def output_body_end
    raise 'Called abstract method: output_body_end'
  end
  def output_end
    raise 'Called abstract method: 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_start
  end
  def output_head
    puts("**** #{@title} ****")
    puts
  end
  def output_body_start
  end
  def output_line(line)
    puts(line)
  end
  def output_body_end
  end
  def output_end
  end
end

 

Then the usage is really straight:

 

 

report = HTMLReport.new
report.output_report
report = PlainTextReport.new
report.output_report

 

Ruby doesn't support abstract methods and abstract classes, then we can use the methods which raise exception meet our demand.

 

"In the Template Method pattern, the abstract base class controls the higher-level processing through the template method; the subclasses simply fill in the details."

 

 

Then it goes to hook methods. but really, I don't agree with the writer's opinion about the example 

Report with the default method implementations. Maybe the default implementations will brought in some wrong format if the coder obmit to implement some methods, such as missing the output_start or output_end or something context related.

So maybe we should implement the must be right thing for the common abstract class.

Lazziness must be secondary in front of correctness

 

Then we go to duck typing issues:

 

If it looks like a duck and quacks like a duck, then it is a duck~

 

The statically typed languages are working like aristocracies, they always ask about your genealogy.

The dynamically typed language are working like meritocracies, they only concern about what you have rather than where do you get the methods from.

 

The writer wrote it at the end of the part~

 

Dynamically typed languages rarely ask about an object’s ancestry; instead, they simply say, “I don’t care who you are related to, Mac. All I want to know is what you can do.”

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值