This log covers 14 design pattern (out of 21 original GoF patterns) in Ruby.1 These patterns are Template Method, Strategy, Observer, Composite, Iterator, Command, Adapter, Proxy, Decorator, Singleton, Factory Method, Abstract Factory, Builder and Interpreter.

Meta-design patterns,2

  • Separate out the things that change from those that stay the same
  • Program to an interface over inheritance
  • Prefer composition over inheritance
  • Delegate

Bonus Point,

  • You ain’t gonna need it

Template Method

Template Method builds an abstract base class with a skeletal methods (Template Methods). The abstract class controls the higher-level processing through the template method; the subclass fill in the details.

Imgur

Before using Template Method pattern,

class Report
  def initialize
   @title = 'Report Title'
   @text =  ['lorem...', 'lorem...']
  end

  def output_report(format)
   if format == :plain
     # Output plain content
   elsif format == :html
     # Output HTML header
   else
     raise "Unknown format: #{format}"
   end

   @text.each do |line|
     if format == :plain
       #  Output plain
     else
       # Output HTML body
     end
   end

   if format == :html
     # Output HTML footer
   end
  end
end

Code above mixes up code that is changing with code that is not changing.

Code below implements class above using Template Method pattern,

class Report
  def initialize
   @title = 'Report Title'
   @text =  ['lorem...', 'lorem...']
  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 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

report = PlainTextReport.new
report.output_report

Hook Methods are non-abstract methods that can be overridden in the concrete classes. It allow concrete class to override the basic implementation or accept the default.

This “I am what I am” approach to typing has been called duck typing. If it looks like a duck and quacks like a duck, then it is a duck.

Duck Typing is a trade-off between compile-time safety and (code clarity and programming flexibility).

Statically typed (e.g. Java) languages are like aristocracy (/ˌarɪˈstɒkrəsi/, 贵族), family tree matters. Dynamically typed (e.g. Ruby) languages are like meritocracies (/ˌmɛrɪˈtɒkrəsi/, 精英管理体制), which only care what a object can do.

Using and Abusing

Using

Start with one variation and refactor the method that will become the template method so that it calls other methods for the variable parts of the algorithm. Create subclass for the first case (Superclass) and move the specific implementation into the subclass.

Abusing

Overdo things in an effort to cover every possibility. The Template Pattern is at its best when it is at its leanest (Everything methods are there for a reason). Also Use hook methods with caution.

Strategy

  1. https://www.safaribooksonline.com/library/view/design-patterns-in/9780321490452/ch01.html

  2. https://www.safaribooksonline.com/library/view/design-patterns-in/9780321490452/ch01.html