Aprende a programar con Ruby

Herencia de clases

La herencia de clases es una relacción entre dos clases. La ventaja de la herencia es que las clases que en una jerarquía están en un nivel inferior, heredan las características de las clases de niveles superiores; y además, pueden añadir sus propias características.

Por ejemplo: todos los gatos son mamíferos. Si todos los mamíferos respiran, la clase gato por descender de la clase mamífero hereda esta característica: los gatos respiran.

Esto puede programarse así:

class Mamifero
  def respirar
    puts 'inspirar, espirar'
  end
end

# el símbolo < indica que
# Gato es una subclase de Mamifero

class Gato < Mamifero
  def maullar
    puts 'Miaaaaaaaaaaau'
  end
end

cribas = Gato.new
cribas.respirar
cribas.maullar

Aunque no se especificó que los gatos puedan respirar, todos los gatos herederán esa característica de la clase Mamifero, ya que el gato es una subclase de los mamíferos. En el argot, Mamifero es la super-clase o clase padre, y Gato es la subclase, o clase hija. Esto es una ventaja para el programador: los gatos tienen la capacidad de respirar, sin haberlo implementado.

En Ruby, como se mostró en este esquema, la clase Object es la madre de todas las clases en Ruby; por lo tanto, sus métodos están disponibles en todos los objetos, excepto aquellos que se han sobrescrito.

Sobrescritura de métodos (method overriding)

Habrá situaciones donde las propiedades de una super-clase no deberían ser heredadas por una subclase en particular. Por ejemplo, las aves generalmente saben volar, pero los pingüinos son una subclase de Ave, y no vuelan:

class Ave
  def asear
    puts 'Me estoy limpiando mis plumas.'
  end

  def volar
    puts 'Estoy volando.'
  end
end

class Pinguino < Ave
  def volar
    puts 'Lo siento, no soy capaz de volar.'
  end
end

p = Pinguino.new
p.asear
p.volar

Se ha sobrescrito el método volar. La gran ventaja que aporta el uso de la herencia de clases, se llama programación diferencial: vamos de lo más general a lo más particular, añadiendo y modificando donde sea necesario.

Los dos ejemplos anteriores son traducciones de la guía online "Ruby User's Guide".

Super

class Bicicleta
  attr_reader :marchas, :ruedas, :asientos # se hablará de attr_reader
  def initialize(marchas = 1)
    @ruedas = 2
    @asientos = 1
    @marchas = marchas
  end
end

class Tandem < Bicicleta
  def initialize(marchas)
    super
    @asientos = 2
  end
end

t = Tandem.new(2)
puts t.marchas
puts t.ruedas
puts t.asientos
b = Bicicleta.new
puts b.marchas
puts b.ruedas
puts b.asientos

Cuando uno usa super dentro de un método, Ruby manda un mensaje a la clase madre del objeto al que pertence el método, buscando un método con el mismo nombre. Si:

  • se invoca con una lista vacía de argumentos (como este caso), super ó super(), no se pasan argumentos al método de la clase madre.
  • se invoca con argumentos, super(a, b, c), se mandand los argumentos a, b, c.

En este caso, se usa super en el método initialize de Tandem, lo que provoca el uso del initialize de Bicicleta para crear instancias de Tandem. La salida es:

2  
2  
2  
1  
2  
1

RAILS: la herencia de clases es una de las claves en el desarrollo de RAILS