Teoría de Objetos

Objetos

Un objeto es un tipo de datos que incorpora datos y código (comportamiento) en un solo "paquete". Ántes de la era de la orientacion a objetos, el código y los datos eran dos cosas separadas. La orientación por objetos nos permite representar de un modo mucho más conveniente al mundo real.

¿Cómo podemos modelar un objeto del mundo real con objetos "de computadora"? Veamos un ejemplo:

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario. Para este juego queremos diseñar un Bonito Delfín que va a brincar con el aro y jugar con la pelota, pero queremos en el futuro extender el juego para cualquier tipo de animal marino porque va a ser una simulación bien picuda. Tal como en el mundo real, necesitamos comenzar con un objeto llamado "pescado" (Para los amantes de la biologia: Ya se que el delfín es un mamífero y no un pescado, pero éste es un ejemplo). El objeto pescado tiene sus datos, como son alto, largo, peso y color. Pero el pescado tambien puede hacer otras cosas, como por ejemplo nadar y sumergirse. Entonces primero hacemos nuestro objeto pescado, que tiene la siguiente forma:

class Pescado
 
  def Pescado
    @largo = 200
    @alto  = 50
    @ancho = 50
    @peso  = 350
  end
 
  def nadar
    # Codigo...
  end
 
  def sumergirse
    # Codigo...
  end
 
end

Este código le dice a la computadora: Pescado es una clase (una clase es una definición de un objeto). Tiene los campos Largo, Alto, Ancho y Peso, que son números de punto flotante. Sus métodos públicos (lo que todo mundo sabe que un pez puede hacer) son Nadar y Sumergirse.

Si esto parece complejo, por favor sigan leyendo. Muy pronto todo quedará claro.

Ahora el Delfín. He decidido para este ejemplo que hay dos clases de delfines, los entrenados y los salvajes (no entrenados). Asi que comencemos con el delfin entrenado:

class Delfin < Pescado
  def tomar_aire
    # Codigo..

  end
 
  def haz_ruido
    # Codigo..
  end
end

Ahora bien, este codigo le dice a la computadora: El Delfin es una clase que hereda de Pescado (o "Un Delfin es un Pescado"). Esto quiere decir que un Delfin puede hacer todo lo que un pescado puede hacer (tiene largo, alto, ancho, peso y además puede nadar y sumergirse). Entonces yo ya terminé mi delfin, y no tuve que implementar de nuevo las funciones para nadar y sumergirse, que el pescado (y ahora tambien el delfin) puede hacer. Ahora vamos a entrar en la materia del jueguito, el delfin entrenado:

class DelfinEntrenado < Delfin

  def juega_con_pelota(segundos)
    # Codigo
  end

  def brinca_el_aro(circunferencia)
    # Codigo
  end

end

El DelfinEntrenado es una clase que hereda no de Pescado, sino de Delfin (o "Un delfín entrenado sigue siendo un delfin, pero..."). Al igual que la vez anterior, un delfín entrenado puede hacer todo lo que un delfin puede hacer, pero además puede jugar con pelota y brincar el aro.

¿Porqué hacer tres objetos nada más para representar un delfín? Supongamos que ahora quiero hacer un tiburón...

class Tiburon < Pescado

def Tiburon
@dientes = 200
@bocon = true
@come_hombres = false
end

def enojate
end

def come_persona(sabroso)
end

def espanta_visitantes
end

end

Gracias a la orientación a objetos, ahora estoy "re-utilizando" el código que usé para implementar mi delfín. Ahora, si mañana descubro que los pescados pueden nadar de una manera especial, o quiero hacer la simulación detallada y quiero hacer que hagan algo más, como nacer y morirse, todos los objetos de tipo pescado (tiburon, delfín, delfín entrenado, pez dorado) van a nacer y morir igual que el pescado, porque la implementación aplica al tipo y a todos los tipos de la misma clase. Ahora bien, la "jerarquía" de los objetos que hemos hecho es como sigue:

Object
+----- Pescado
|
+----- Delfin
| |
| +----- Delfin Entrenado
|
+----- Tiburon

La jerarquía de objetos es una especie de "árbol genealógico" que nos dice qué objetos se "derivan" de otros objetos. Como conceptualizamos esta jerarquía? Es de hecho bastante sencillo una vez que nos acostumbramos al árbol. Por ejemplo, supongamos que queremos saber que interfaces soporta el "Delfín Entrenado". Leemos todos los "padres" de la siguiente manera: "Un Delfin ES UN Pescado, que ES UN Objeto". Esto quiere decir que un objeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfin y de la clase Pescado.

Tipos en Ruby

Los lenguajes orientados a objetos son típicamente de tipos fuertes o tipos débiles.

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver si son del mismo tipo antes de la ejecución (al tiempo de compilar). Un lenguaje de tipos débiles sólo revisa al tiempo de ejecución.

La evaluación de tipos en ruby es un poco especial. En ruby, los tipos están definidos como las capacidades de un objeto, en vez de estar definidos arbitrariamente por naturaleza. En otros lenguajes, esto se llama polimorfismo, y lo consiguen mediante interfaces. En Ruby, las inerfaces no son necesarias.

Los rubyistas le llaman "evaluación tipo Pato", por el dicho en Inglés que va "Si camina como un pato, y habla como un pato, es un pato"

Esto quiere decir que ruby intentará ejecutar los métodos de su objeto incluso cuando los típos sean diferentes. En nuestro ejemplo anterior, si le añadieramos al Tiburón un método brinca_el_aro: 

class Tiburon < Pescado
def brinca_el_aro(circunferencia)
end
end

Nuestro código intentaría ejecutarlo incluso cuando fué diseñado para un DelfínEntrenado.