Duck Typing in Ruby
Bài đăng này đã không được cập nhật trong 3 năm
Duck Typing?
If you are familiar with Ruby, you'll have noticed that in Ruby we don't need to declare the types of the variables or return type of a method. This is one of the properties of dynamic programming language.
Some languages are statically typed, means the types are enforced at compile time. Languages like Java and C++ are statically typed languages. On the contrary, you have dynamically typed languages like Ruby and Python. Dynamic typing is more flexible and any type restrictions would have to be made at runtime.
Objects in Ruby, for example, are defined by the methods on them and not what type of thing they are. This idea of an object being defined by the messages it responds to is what duck typing is all about.
The name duck typing comes from the saying, “If it walks like a duck, and quacks like a duck, then it must be a duck.” In other words, If an object behaves like a duck then we will treat it like a duck, even if it isn't an actual duck.
Example
Consider these scenario,
class Egg
def prepare
puts "Egg is done."
end
end
class Bread
def prepare
puts "Bread is done."
end
end
class Breakfast
def self.combo1
Egg.new.prepare
Bread.new.prepare
end
end
Breakfast.combo1
We have 2 food classes here, Egg
and Bread
each with a method that will prepare the food for the Breakfast
class. Another class Breakfast
has a class method combo1
. So if we want combo1 for breakfast we can just call this method. Nice.
By inspecting the combo1
method, we can clearly see that, this method dependent on 2 classes Egg
and Bread
. It relies on specific classes and has the explicit names of those classes. It knows the names of the messages that each class understands, along with the arguments that those messages require. All of this knowledge increases risk; many distant changes will now have side effects on this code.
Finding the duck
Both Egg
and Bread
classes serve the similar purpose prepare
. It means, Egg
and Bread
both behaving like the same thing food (duck) and also contains similar action prepare
(quack).
So we can treat them both as a similar object and remove the direct dependencies from the combo1
method to make it more abstract, flexible and scalable.
Refactored code will look like this,
class Breakfast
def self.combo1 *foods
foods.each do |food|
food.prepare
end
end
end
Breakfast.combo1 Egg.new, Bread.new
Both Egg
and Bread
classes serve the similar purpose prepare
. It means, Egg
and Bread
both behaving like the same thing food (duck) and also contains similar action prepare
(quack).
So we can treat them both as a similar object and remove the direct dependencies from the combo1
method to make it more abstract, flexible and scalable.
If we need to add one more item to our Breakfast combo1
menu we can just pass that object as a param.
Breakfast.combo1 Egg.new, Bread.new, Butter.new
The code is more scalable now, right? It will be a lot easier to extend or improve some of the features in future and gives you more freedom.
Wrap up
Its pretty clear to see the flexibility that duck typing can bring to your application. Many of your favorite libraries and even the Ruby language itself makes heavy use of them. Duck typing will reduce many of the costly dependencies on classes and give you flexible environment to design your application. This will allow our objects to ask for what they want without knowing how to get it, and thus give us a more maintainable application.
References: http://www.poodr.com/ http://rubylearning.com/satishtalim/duck_typing.html https://revelry.co/duck-typing-with-ruby/
All rights reserved