Recently, I decided to take quick read of the Russ Olsen’s Design Patterns in Ruby just in case the book had interesting ways of solving common problems. The book tends to digress into type safety (the lack of it) and other gizmoz that Rubyists defend and evangelize. Hence, I decided to write this article that will simply show you the code for the most important patterns. I have just covered the most elegant way these can be used. For what its worth, this is really the only reason you would want to read this book.
Having said that, I assume that you can take a judgement on when these patterns are to be used. That will truly determine whether/if it solves a problem for you. This post is just about doing it the Ruby way.
Template Method
Wiki Link. This pattern is among the oldest ones and has inherent support in most language constructs(Java interfaces )
class Bird
def chirp
raise "I dont know how to chirp. I only know that bird must chirp"
end
end
class Duck < Bird
def chirp
puts "quack"
end
end
Duck.new.chirp # quack
Strategy
The most obvious problem with the above implementataion arises when learn from Darwinian theory that Ducks may not just quack but may speak too.
class BirdShout
def chirp
raise "I dont know what to do"
end
end
class Quack < BirdShout
def chirp
puts "Quack"
end
end
class Tweet < BirdShout
def chirp
puts "I thought I taw a putty tat"
end
end
class Duck
def initialize strategy
@chirper = strategy
end
def chirp
@chirper.chirp
end
end
Duck.new(Quack.new).chirp #Quack
Duck.new(Tweet.new).chirp #I thought I taw a putty tat
The base class in this example is clearly optional (It can be removed from the code literally along with the subclass constructs with little consequence). In a duck typed language like Ruby, a base class default implementation is asymmetric with the rest of the language’s philosophy.
This can be however had for those of you are still insecure about Ruby ‘s type system.
This can also be implemented using ruby’s Proc objects:
class Duck
def initialize(&strategy)
@chirper = strategy
end
def chirp
@chirper.call
end
end
Duck.new{puts "Quack"}.chirp
The observer
Ruby constructs do not significantly influence this pattern. Wiki Link
class CompanyStock
attr_accessor :price
def initialize
@observers = []
end
def add_observer observer
@observers << observer
end
def price= new_price
unless price == new_price
@price = new_price
notify_observers
end
end
def notify_observers
@observers.each do |o|
o.notify(self)
end
end
end
class PotentialBuyer
def notify stock
puts stock.price
end
end
class PotentialSeller
def notify stock
puts stock.price
end
end
stock = CompanyStock.new
stock.add_observer(PotentialBuyer.new)
stock.add_observer(PotentialSeller.new)
stock.price = 10
One sizable influence Ruby can have is, instead of passing the Observer objects, we could pass in Observer code blacks with the CompanyStock’s notify method invoking a “call” on the procs to notify.
One Trackback/Pingback
[...] Part1 Composite Pattern [...]