Polimorfismo
Explicación del concepto de polimorfismo, tipos y aplicaciones reales.
CÓDIGO FUENTE
Se ha añadido una clase SlimeFuego para trabajar éste tema:
CLASES ABSTRACTAS
Una clase abstracta es aquella que está marcada con el modificador abstract
en su declaración. Esto evita que se creen instancias de la clase, pero no impide que se creen subclases a partir de ella.
Las clases abstractas son una pieza fundamental del polimorfismo ya que implementan métodos y atributos genéricos para que las subclases los puedan heredar, facilitando así la abstracción.
La diferencia entre utilizar una clase abstracta y una clase abierta para heredar es la capacidad de crear instancias de la primera. Sin embargo, ¿Cuándo utilizar una clase abstracta?
Toda clase abstracta debe contener al menos un método abstracto.
Métodos y Atributos abstractos
Los miembros de una clase abstracta también pueden ser marcados como abstract
, lo que significa que no tendrán implementación, debido a que esta será exigida para las subclases.
POLIMORFISMO
El polimorfismo es una de las características más importantes de la POO. Permite utilizar una interfaz única para hacer referencia a objetos de diferentes tipos. Existen dos tipos:
Polimorfismo paramétrico
Permite que una función se escriba de forma genérica, de modo que pueda manejar valores de manera uniforme sin depender de su tipo.
Este tipo de polimorfismo es tan común que se llama simplemente "Polimorfismo".
Funciones Polimórficas:
Una función que puede evaluarse o aplicarse a valores de diferentes tipos se conoce como función polimórfica.
Para aplicar el polimorfismo paramétrico se puede hacer de dos maneras:
Polimorfismo paramétrico por herencia
En este caso, vamos a implementar la función de combate "fight(Slime1, Slime2)
".
Sin embargo, si no existiera el polimorfismo paramétrico tendría que implementar dicha función varias veces, cada una de ellas con unos argumentos diferentes en función del tipo de los Slime que combatan.
Gracias al polimorfismo y a la clase padre Slime que engloba a todas las clases hijo de SlimeTipo, podemos implementar una sola vez la función:
Como vemos, la función coge como argumentos dos objetos de tipo Slime
. Esto hace que todos los objetos que sean inferiores a Slime
en el árbol genealógico puedan entrar en esa definición.
Ese es el motivo por el que la llamada a la función fight no da error.
Polimorfismo paramétrico por clases abstractas
Lo mismo podemos hacer con una clase abstracta. De hecho, la clase Slime podría ser perfectamente una clase abstracta pues tiene un método "attack
" que podríamos considerar abstracto y no se espera que se generen instancias de ella. Vamos a verlo muy resumido para el ejemplo:
Con lo anterior, obligamos a cada una de las diferentes clases hijo a implementar su propia función attack
.
Con los cambios que se han realizado, el ejemplo anterior funciona perfectamente, ya que en vez de heredar desde una clase open
, heredan desde una clase abstract
.
Sin embargo, ahora ya no se pueden crear objetos tipo Slime puesto que es una clase abstracta.
De la misma manera hemos aprendido a utilizar las funciones abstractas para generar funciones que aun llamándose igual, se comportan diferente en función del tipo del objeto. Esto es parte del polimorfismo de subtipo que vamos a ver ahora.
Polimorfismo de subtipo
Como ya hemos visto en el anterior ejemplo, puede darse el caso de que tenga un método de la clase padre que en una de las clases hijo se comporta diferente a como se comporta en la clase padre.
En este caso vamos a estudiar dos posibilidades:
override
La palabra reservada override
se utiliza en las clases hijo que desean cambiar el código de un método de la función padre por uno personalizado:
Para el ejemplo vamos a volver a poner la clase Slime como clase open.
Como vemos, la función attack
ya no puede ser abstract
pues daría error, para que se pueda sobreescribir como hemos hecho antes, utilizamos la palabra reservada open
en la función tambien.
super
Al contrario que la palabra reservada override, la palabra reservada super llama a una función de la clase padre. En el caso del ejemplo nos va a quedar muy claro:
De esta manera, cuando lancemos la función fight
, el log de la batalla quedará de la siguiente manera:
Last updated