Community Oriented
Gems
Web Based
Projects For Me
The Template and Strategy patterns
Exploring design patterns, 1 Sep 2011
Yesterday Doug showed me the Template and Strategy design patterns. Here's a quick rundown in Ruby. Note that I'm showing them as close to their static language implementation as possible.
Template pattern
So you need some object that prints "Hello, ____!"
, but the code that decides which word goes where the blank is needs to be able to change. The Template pattern would have you create a subclass with the customized code:
class Greeter def to_s "Hello, #{name}!" end # This method isn't necessary in Ruby, but static languages # like Java would require you to declare it as abstract def name raise 'Should be overridden' end end class GreetNamed < Greeter attr_accessor :name def initialize(name) self.name = name end end GreetNamed.new("Joe").to_s # => "Hello, Joe!"
Of course, this allows us to specify many possible implementations. For example, here is a class that will read the name from standard input, and write the greeting to standard output.
class GreetFromStdin < Greeter def name puts "What's your name?" gets.chomp end end puts GreetFromStdin.new
And because this is Ruby, we can override on the fly (Actually, Java can do this one, too).
greeter = Greeter.new def greeter.name "Amar" end greeter.to_s # => "Hello, Amar!"
Strategy pattern
Another pattern, and Doug prefers this as it has looser dependencies, is for the greeter to have an object which implements the method it needs.
class Greeter attr_accessor :namer def initialize(namer) self.namer = namer end def to_s "Hello, #{namer.name}!" end end # This class isn't necessary in Ruby, but it is in statically typed # languages. In Java, it would be an interface. class Namer def name end end # A class that specifies the name on instantiation class GreetNamed < Namer attr_accessor :name def initialize(name) self.name = name end end namer = GreetNamed.new "Joe" Greeter.new(namer).to_s # => "Hello, Joe!"
And because this is Ruby, you don't need to inherit from the Namer, Any object which has a name method will do.
require 'ostruct' namer = OpenStruct.new :name => "Ayaan" Greeter.new(namer).to_s # => "Hello, Ayaan!"