Se entiende por overriding la posibilidad de reemplazar la conducta de un método en la superclase.
[19:28][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ cat overriding_methods.rb class WorldGreeter def greet # Display a greeting puts "#{greeting} #{who}" end def greeting # What greeting to use "Hello" end def who # Who to greet "World" end end # Greet the world in Spanish class SpanishWorldGreeter < WorldGreeter def greeting # Override the greeting "Hola" end end # We call a method defined in WorldGreeter, which calls the overridden # version of greeting in SpanishWorldGreeter, and prints "Hola World" SpanishWorldGreeter.new.greet
Ejecución:
[19:28][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ ruby overriding_methods.rb Hola World
[19:34][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ cat abstract_and_concrete_classes.rb # This class is abstract; it doesn't define greeting or who # No special syntax is required: any class that invokes methods that are # intended for a subclass to implement is abstract. class AbstractGreeter def greet puts "#{greeting} #{who}" end end # A concrete subclass class WorldGreeter < AbstractGreeter def greeting; "Hello"; end def who; "World"; end end WorldGreeter.new.greet # Displays "Hello World"
Ejecución:
[19:34][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ ruby abstract_and_concrete_classes.rb Hello World
El siguiente ejemplo ilustra el problema:
[~/srcLPP/Chapter7ClassesAndModules/overriding_methods]$ cat overriding_private_methods.rb class MotherFoo def titi foo end private def foo "mother foo" end end class ChildFoo < MotherFoo def foo "child foo" end end c = ChildFoo.new puts c.titi # child foo print "Private methods of mother class: " class MotherFoo puts MotherFoo.private_instance_methods(false) end
La llamada a titi
hace que se llame al método foo
de la clase hija en vez
de al método foo
de la clase madre que era lo que el programador pretendía.
Una manera de paliar este problema consiste en documentar los métodos privados de nuestra clase en una sección para desarrolladores.
Como muestra la ejecución del anterior ejemplo
siempre es posible averiguar que métodos privados tiene la superclase llamando a
MotherFoo.private_instance_methods
. De esta forma sabemos que nombres
evitar en nuestra clase hija:
[~/srcLPP/Chapter7ClassesAndModules/overriding_methods]$ ruby overriding_private_methods.rb child foo Private methods of mother class: foo [~/srcLPP/Chapter7ClassesAndModules/overriding_methods]$
Otra forma de aliviar el problema es:
Proc
o una lambda
11:10][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ cat overriding_private_methods3.rb class MotherFoo @ofoo = Proc.new do |x| "mother foo #{x}" end def self.foo(x) @ofoo.call(x) end def titi(y) MotherFoo.foo(y) end end class ChildFoo < MotherFoo # puts @ofoo.call # generates an exception: undefined method `call' for nil:NilClass (NoMethodError)) def foo(z) "child foo #{z}" end puts MotherFoo.foo(9) end c = ChildFoo.new puts c.titi(4) puts c.foo(3)Como se vé, es todavía posible - pero ahora explicitándolo con
MotherFoo.foo
- acceder al método "privado"
evitando de este modo la colisión casual.
Ejecución:
[11:13][~/Dropbox/src/ruby/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules]$ ruby overriding_private_methods3.rb mother foo 9 mother foo 4 child foo 3
Casiano Rodriguez León 2015-01-07