Repase la sección Clase y Tipo de un Objeto. Polimorfismo 10.8.4.
Red or yellow, black or white, they are all ducks in the VM’s sight.
En programación orientada a objetos, el polimorfismo se refiere a la propiedad por la que es posible enviar mensajes (llamar a métodos) con el mismo nombre a objetos de clases distintas.
El único requisito que deben cumplir los objetos que se utilizan de manera polimórfica es saber responder al mensaje que se les envía.
[~/srcLPPruby/TheRubyProgrammingLanguage/Chapter3DatatypesAndObjects]$ cat type_versus_class_checking.rb # page 75 require "stringio" class Tutu # Appends " chazam!" to its argument def chazam_check(x) # duck typing style raise "Error in chazam_check" unless x.respond_to? :"<<" x << " chazam!" end end if __FILE__ == $0 t = Tutu.new t = Tutu.new puts "procesing a String" p t.chazam_check("ban ban") # "ban ban chazam!"" puts "procesing an Array" p t.chazam_check([1,2,3]) # [1, 2, 3, " chazam!"]" begin puts "Processing a Fixnum" p t.chazam_check(6) # can't convert String into Integer rescue puts "t.chazam_check(6) fails:\n\tException type: <#{$!.class}>\n\tmessage: <#{$!}>" end end
[~/srcLPPruby/TheRubyProgrammingLanguage/Chapter3DatatypesAndObjects]$ ruby type_versus_class_checking.rb procesing a String "ban ban chazam!" procesing an Array [1, 2, 3, " chazam!"] Processing a Fixnum t.chazam_check(6) fails: Exception type: <TypeError> message: <can't convert String into Integer>
[~/srcLPPruby/TheRubyProgrammingLanguage/Chapter3DatatypesAndObjects]$ cat type_versus_class_checking2.rb # page 75 require "stringio" class Tutu # Print the lengths of the lines in the IO object def show_lengths(x) raise "Error in show_lengths" unless x.is_a? IO #raise "Error in show_lengths" unless x.respond_to? "each_line" x.each_line do |line| print "#{line.length} " end puts "" end end if __FILE__ == $0 t = Tutu.new ####################################################### t.show_lengths(IO.open(File.open($0).to_i)) # 10 19 ... begin t.show_lengths(StringIO.open("Hello World!\nHello Mars!")) # Error in show_lengths rescue puts "t.show_lengths fails with StringIO:\n\tException type: <#{$!.class}>\n\tmessage: <#{$!}>" end end
[~/srcLPPruby/TheRubyProgrammingLanguage/Chapter3DatatypesAndObjects]$ ruby type_versus_class_checking2.rb 10 19 11 52 22 52 68 26 30 8 12 6 4 1 18 15 1 58 58 8 87 9 100 6 4 t.show_lengths fails with StringIO: Exception type: <RuntimeError> message: <Error in show_lengths>Aunque quizá sea larga y requiera para su comprensión completa mas conocimientos de los que tenemos en este punto, escuchar la charla Less: The Path to a Better Design por Sandi Metz en Vimeo puede resultar útil. Metz muestra como el uso de Tipado Pato (Duck Typing) puede ayudar a desacoplar nuestras clases, mejorando así nuestros diseños y haciéndo que nuestro software sea mas adaptable a los cambios que necesariamente habrán de sobrevenir durante su vida útil.
Véanse algunos comentarios de Nathan Youngman sobre la lectura del libro "Practical Object Oriented Design in Ruby: An Agile Primer" de Sandi Metz:
Procedural programs operate by performing a series of steps, whereas object-oriented programs are about sending messages.
When one object tells another to perform a series of steps, it knows too much! To minimize dependencies, an object needs to ask for what it wants, and trust that the receiver takes the necessary steps. It doesn't need to know the details.
The distinction between a message that asks for what the sender wants and a message that tells the receiver how to behave may seem subtle but the consequences are significant.
Rather than depending on a concrete Class, consider relying on a duck type that implements the necessary message. Depending on a “duck-like” thing is much more flexible.
Casiano Rodriguez León 2015-01-07