I have been reading "Head First Design Patterns" [1], which used Java to construct all examples. It's made me wonder what would it take to implement same pattern in Ruby. What would be the different, specially Ruby is not "type" language at all.
The first pattern that I am going to try is "Strategy" pattern. The principal behind "Strategy" pattern is "Favor composition over inheritance". It's interesting to see that at least two different way we can implement this principal in Ruby. One using module, another using class.
Let use the same design in the book, the duck design. Since all duck would have name, and can swim. The Duck base class would contain attribute name and method swim(). All duck swim, you know.
Let use the same design in the book, the duck design. Since all duck would have name, and can swim. The Duck base class would contain attribute name and method swim(). All duck swim, you know.
class Duck
attr_reader :name
def initialize
@name = "simple duck"
end
def swim
puts "All duck can swim."
end
end
However, not all duck are fly in the same way. MallarDuck and RedheadDuck will be able to fly with wing, while ToyDuck won't be able to quack or fly at all. To be able to share same behavior between MallardDuck and RedheadDuck, we create a module under then namespace Behavior
module Behavior
module FlyWithWing
def fly
puts "Fly with wing"
end
end
end
module Behavior
module NotFly
def fly
puts "no way I can fly"
end
end
end
class MallardDuck < Duck
include Behavior::FlyWithWing
def initialize
@name = 'Mallard duck'
end
end
class RedheadDuck < Duck
include Behavior::FlyWithWing
def initialize
@name = 'Redhead duck'
end
end
class ToyDuck < Duck
include Behavior::NotFly
def initialize
@name = 'Toy duck'
end
end
irb> ducks = [MallardDuck.new, RedHeadDuck.new, ToyDuck.new]
irb> ducks.each(&:fly)
Fly with wing
Fly with wing
no way I can fly
With proper directory setup, and follow convention. Ruby will be able to find the file that contain module and include it properly with no configuration at all.In this case, each module would contain in each file under directory "behavior". By ruby convention, filename would have to match the module name. That mean the file would be name "fly_with_wing.rb", and "not_fly.rb"
We can also do the same with "quack" behavior, say Behavior::QuackLoudly, Behavior::NotQuack, etc.
As you can see, we can use ruby module to implement composition quite efficiently. It's seem natural to me to use module to break down object into different component and composed them.
Next time, I will describe more in detail of the implementation.
[1] Head First Design Patterns, Eric Freema, Elisabeth Freeman, O'Reilly 2004.
No comments:
Post a Comment