This is the summaries of Duck Typing in Practical Object-Oriented Design: An Agile Primer Using Ruby
Wthat’s Duck Typing?
According to wikipedia,
Duck typing in computer programming is an application of the duck test — “If it walks like a duck and it quacks like a duck, then it must be a duck” — to determine if an object can be used for a particular purpose. With normal typing, suitability is determined by an object’s type. In duck typing, an object’s suitability is determined by the presence of certain methods and properties, rather than the type of the object itself
Well, WTF…!?
In short, object knows how to handle the methods. So whatever it is, all you have to do is to give a method to the object.
Concrete Example
Let’s consider the detail with a Class that handles salary calculations.This class handles how to calculate employees’ salary with case
. In this case, you have to add case logics when new employee type is added, so the method will grow easily and hard to maintain.
class Salary
def calc_salaries(employees)
employees.each do |employee|
case employee
# if employee is proper, use this logic
when Proper
employee.calc_insurance_fee(insurance)
# if employee is part-timer, use this logic
when PartTimer
employee.calc_tax_reduction(working_hour)
# if employee is outsourcing, use this logic
when Outsourcing
employee.calc_special_bonus(special_reward)
end
end
end
end
The method is already 10 lines. If someone who knew Sandi Metz’ Rules For Developers saw this logic, they maybe get pissed off. Of course I will get angry and re-write this logic by myself.
On the other hand,
Each employee object knows which Class it belongs to. So send it a method that calculate its own salary (In this case, let’s make calc_salary), instead of using case
. And add calc_salary method to each employee Class.
class Salary
def calc_salaries(employees)
employees.each do |employee|
# you just call employee's calc_salary method
employee.calc_salary
end
end
endclass Proper
def calc_salary
# write specific logic
end
endclass PartTimer
def calc_salary
# write specific logic
end
endclass Outsourcing
def calc_salary
# write specific logic
end
end
Now calc_salaries method is just 3 lines and you do not need to add specific logic on the method when you have new employee types!
If you want to force each employee to have calc_salary method, you can write like this.
class Employee
def calc_salary
raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
end
endclass Proper < Employee
def calc_salary
# write specific logic
end
endclass PartTimer < Employee
def calc_salary
# write specific logic
end
endclass Outsourcing < Employee
def calc_salary
# write specific logic
end
end
Using inheritance, you can force what to implement on each subclass.
The merit of Duck Typing
You can keep code simply, clearly and transparently.
You do not have to divide logic in a method by objects’ type, so it’s easy to add new classes, and less risk of getting degradations.
The demerit of Duck Typing
Basically there is no demerit. If I have to say something, you need to have a skill of OOP (but it is not a demerit at all!!!!)
How to find Duck Typing
If you divided logics by case, kind_of?, is_a? or responds_to, you may miss Ducky!?