Classes, Inheritance and polymorphism

I’m translating this:

Clases, herencia y polimorfismo

Ahora que ya sabes las bases de programación, vamos a ver un paso más avanzado. Primero vamos a aclarar los conceptos de clase, herencia y polimorfismo. Luego, veremos UML para explicar el ejemplo que vamos a hacer (UML es una forma de representar mediante gráficos un conjunto de clases y su relacción entre ellas), y finalmente haremos el ejemplo.

Clases:

Como dijimos en el capitulo anterior, una clase es una colección de variables y funciones que indica como serán los objetos que se hagan de ella. Sería un molde de repostería del que sacamos los distintos objetos-pasteles. El ejemplo sería que tenemos la clase persona, que se compone de las variables fecha de nacimiento, telefono y nombre, y la función de calcular la edad. Y de esa clase podremos hacer varios objetos. Por ejemplo:

  1. Nombre= PericoFecha nacimiento = 1991

    Telefono = 11111111

  2. Nombre= FulanoFecha nacimiento = 1977

    Telefono = 2222222

  3. Nombre= FulanoFecha nacimiento = 1977

    Telefono = 2222222

¿Los dos objetos del final son iguales? No, tienen el mismo valor, pero están alojados en distintos puntos de la memoria y se tratan como dos objetos diferentes. Es como si tienes una variable numerica llamada X con el valor 5 y otra variable numérica llamada Y con el valor 5. No son la misma variable, pero tienen el mismo valor.

El objetivo de las clases es agrupar variables y funciones en grupos lógicos (como la citada persona) pero también encapsular esa información. Por ejemplo, imagina que tenemos otra clase llamada DNI. Esa clase puede tener las mismas variables y funciones que una persona. Entonces… ¿Para que hacer la clase persona? Pues porque así en vez de tener en la clase DNI las variables de la persona y las variables del dni (como material de fabricación, fecha de expedición, tamaño…), puede tener un objeto de la clase persona y luego el resto de variables propias del DNI, y si la clase persona tiene datos que son privados, la clase DNI no podrá acceder a ellos. Los datos de la persona estan encapsulados en su clase. Y el código final es más fácil de leer al reducir la función de calcular la edad, nombre, telefono y fecha de nacimiento a solo crear un objeto y llamar a las partes necesarias. Esto último lo verás en el ejemplo al final.

Herencia:

Una vez que tienes una clase lista y terminada, y tienes que crear una nueva clase que comparte muchas cosas en común, es posible crear una clase con las cosas que tienen ambas clases en común y hacer que estas dos clases hereden de la clase „padre“ (la que tiene las cosas en común) y en las clases „hijas“ se pondrán las cosas específicas de cada una.

Un ejemplo típico es decir que tenemos la clase “Coche“, con su depósito, puertas, tamaño, etc… ¿Que pasa si queremos hacer la clase „Motocicleta“? Para empezar no tiene puertas…

La solución es crear una clase padre que podríamos llamar „vehiculo“, que tiene las variables comunes como el depósito, el tamaño, etc. De esa clase heredarán las clases „Coche“ (que añade la variable numero de puertas y maletero) y la clase „Motocicleta“ que añade cilindrada y tipo de carnet.

Polimorfismo:

El polimorfismo es un paso más allá de la herencia. Quiere decir que si creamos un objeto del tipo vehiculo, podemos asignarle un coche o una moto. Por desgracia, el ejemplo pasado no nos sirve sin mas, hace falta hacer un par de cambios:

  • La clase padre tiene que ser abstracta. Esto quiere decir que por lo menos una función no tiene nada de código dentro. Luego lo vemos en el ejemplo.
  • Las clases hijas son las que se encargarán de darle el código.

Para que pueda funcionar, vamos a añadir una función a la clase vehiculo llamada „avanzar“. Esta función será abstracta. No tiene código dentro y se declararía asi:

public abstract void avanzar();

Recuerda del capítulo anterior: Esta función sería publica, se puede llamar. No es estática como la del capítulo anterior, por lo que hace falta crear un objeto de una clase hija (las clases abstractas no pueden tener objetos) para acceder a la función. Indicamos que es abstracta con „abstract“, la función se llama „avanzar“, y como no tenemos código ponemos el punto y coma al final.

Luego las clases hijas tendrían por ejemplo en la moto:

@override

public void avanzar(){

System.out.println(„giro el puño de aceleración“);

}

Mientas en el coche tendría:

@override

public void avanzar(){

System.out.println(„piso el pedal de aceleración“);

}

El @override indica al programa que estas reescribiendo una función de la clase padre. Esto se puede hacer también en herencia.

Finalmente, cuando vaya a usar uno u otro, pondré en la función main algo como:

vehiculo veh = new moto();

veh.avanzar();

veh = new coche();

veh.avanzar();

Vaya, aquí es la primera vez que hemos creado un objeto y no te he hablado todavía de los constructores de objeto. Eso lo explico en el ejemplo más adelante. Con esto te digo que el resultado es:

giro el puño de aceleración

piso el pedal de aceleración

Has creado un solo objeto, que has hecho que sea una moto, y luego un coche, y usando la misma función tiene resultados distintos. Esto es bueno para mantener el código, dar una jerarquía mejor, y dar un patrón de comportamiento a las clases hijas (porque si solo hubiera herencia, al ser funciones que hacen distintas cosas no las veríamos como algo común para la clase padre, y podrían llamarse de forma distinta y no se podría automatizar el avanzar independientemente de si es un coche o una moto)

Leave a Reply