Basic Polymorphism
In Ruby, inheritance polymorphism can be achieved doing something like the following:
class Bird
def initialize(name)
@name = name
end
def speak
puts 'Tweet'
end
def fly
puts 'Up up and away...'
end
end
This is our base class, Bird. All other classes will inherit the methods in this class.
class Duck < Bird
def speak
puts "Quack I am #{@name}"
end
end
class Penguin < Bird
def speak
puts "Squak I am #{@name}"
end
def fly
puts 'Nope. I swim...'
end
end
These are the classes that inherit from our base class. Ducks and Penguins are Birds. So, they will have basic methods speak() and fly(). The cool thing is we can override existing methods of the superclass from within the subclass to change the default behavior of a Bird. For example, Penguins don't tweet or fly. So, we override the base methods to better reflect the behavior of penguins.
So, now we can do something like this:
birds = [Bird.new('Tweetie'), Duck.new('Donald'), Penguin.new('Mumbo')]
birds.each do |b|
b.fly
end
# Up up and away...
# Up up and away...
# Nope. I swim...
birds.each do |b|
b.speak
end
# Tweet
# Quack I am Donald
# Squak I am Mumbo
The Ruby Way
In Ruby, traditional methods of polymorphism (seen above and in languages such as Java) are not widely accepted. A concept known as "duck typing" is preferred. You can read more about duck typing here.Basically, we follow a simple rule: If it walks, swims, and quacks like a duck, I call that bird a duck
We can get the same type of "polymorphic" behavior by simply implementing each method individually in each class and including any common methods:
class Duck
def speak
puts "Quack I am #{@name}"
end
def fly
puts 'Up up and away...'
end
end
class Penguin
def speak
puts "Squak I am #{@name}"
end
def fly
puts 'Nope. I swim...'
end
end
Now, each type of Bird has its methods individually defined according to its own specific behavior. What about the shared initialize() constructor?
module Bird
def initialize(name)
@name = name
end
end
We put any shared methods in a module. This way, we can include them in our classes:
class Duck include Bird ... end class Penguin include Bird ... end
Do It Your Way
I have no strong opinion on whatever approach you decide to use. There are evangelists on both ends who live and die by either one. Solve your problem any way you please!Resources:
Ruby polymorphism discussion: http://stackoverflow.com/questions/137661/how-do-you-do-polymorphism-in-ruby
The Ruby Way excerpt: http://books.google.com/books?id=ows9jTsyaaEC&pg=PA14
Ruby Learning: http://rubylearning.com/satishtalim/ruby_inheritance.html
Very nice, thank you. Is duck typing intended to fully replace inheritance, or are there some cases where inheritance is preferred, even in ruby?
ReplyDelete