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