December 03, 2007 by alex
I recently read Kent Beck’s new book Implementation Patterns - it was a nice read and I guess it somehow strengthened my senses towards patterns a bit. Unfortunately it is written with Java in mind, and as we all know Patterns are language specific. The following can’t really be applied to Java as far as i know (having stopped writing in Java with 1.5). So I discovered a kind of implementation pattern I had used a few times in the last weeks. Maybe everyone has already written about it but I want to stress that I discovered it myself :) Here it is:
When to use it: When you have a complicated if-elseif-elsif-else or switch clause and want to replace it with something more elegant.
When not to use it: It works well for limited complexity. I things get more complex you may want to use class inheritance instead.
What it does: Put the each condition and the according logic into a hash. Then iterate through the conditions to find a match and execute its logic.
Suppose you have a class Video
that represents a video on youtube or some other hosting provider. Its purpose is to render the neccessary HTML tags to embed it into a document. The generated HTML differs depending on the hosting provider, e.g. youtube.com or vimeo.com. The code could be expressed like this:
class Video
def initialize(url)
@url = url
end
def html
if @url.include?('youtube.com')
"<embed>player.youtube.com/#{@url}</embed>"
elsif @url.include?('vimeo')
"<embed>vimdeo.com/player/#{@url}/1</embed>"
end
end
end
Using the selector pattern it might look like this:
class Video
@@renderers = {
'youtube.com' => lambda{|url| "<embed>player.youtube.com/#{url}</embed>"},
'vimeo' => lambda{|url| "<embed>vimdeo.com/player/#{url}/1</embed>"}
}
def initialize(url)
@url = url
end
def html
select_provider.call(@url)
end
private
def select_provider
@@renderers.select{|provider, code| @url.include?(provider)}.first.last
end
end
With only 2 providers this doesn’t make too much sense but with something like 5 your elsifs
start to get really ugly and the selector pattern offers a more ligtweight way to replace these than creating an entire hierarchy of subclasses for every case.