"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck." Duck types are public interfaces that are not tied to any specific class. They are about the object's methods and properties, rather that its inheritance from a certain class. In a nutshell:
Behaviour over class membership
Following that pattern helps to improve:
- readability (less code for all message sender)
- add enormous flexibility
- reduces class coupling and therefore increases maintainability
class Drug
attr_accessor :dope, :brand
end
class Food
attr_accessor :ingredients
def labeling
ingredients.map { |ingredient| ingredient.name }.join(', ')
end
end
class Clothing
attr_accessor :name
end
and a Bill class for printing out:
class Bill
def print_name product
return puts "#{product.brand} (#{product.dope})" if product.respond_to? :dope
return puts product.labeling if product.respond_to? :labeling
puts product.name
end
end
The Bill#print_name can be refactored by also duck typing the 3 classes:
class Drug
attr_accessor :dope, :brand
def name
"#{product.brand} (#{product.dope})"
end
end
class Food
attr_accessor :ingredients
def labeling
ingredients.map { |ingredient| ingredient.name }.join(', ')
end
alias_method :name, :labeling
end
class Clothing
attr_accessor :name
end
All 3 classes now respond to name and can called in Bill#print_name like:
class Bill
def print_name product
puts product.name
end
end
Further articles of interest:Supported by Ruby 2.1.1
Keine Kommentare:
Kommentar veröffentlichen