六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 130|回复: 0

Design Patterns in Ruby [Digest 2]

[复制链接]

升级  8.67%

15

主题

15

主题

15

主题

秀才

Rank: 2

积分
63
 楼主| 发表于 2013-2-7 21:14:15 | 显示全部楼层 |阅读模式
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>')   endend 

The usage of the class is as below:
report = Report.newreport.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'  endend 
 
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>')  endend 
 
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  endend 
Then the usage is really straight:
 
 
report = HTMLReport.newreport.output_reportreport = PlainTextReport.newreport.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.”
 
 
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表