Sin mas rodeos, a lo que vinimos.....
Para este ejemplo vamos a trabajar usando una Interface, una clase Abstracta y 2 clases Concretas como vemos en el siguiente diagrama:
Podemos ver que se tiene un árbol de herencia definido, donde la clase Abstracta Animal implementa la interface IAnimal y al mismo tiempo es clase Padre de Gato y Perro, los cuales implementaran no solo los métodos abstractos de Animal sino también el método comunicarse() de la interface IAnimal.......en entradas anteriores vimos que una de las reglas al trabajar con clases abstractas o interfaces es que todas las clases concretas que desciendan de ellas, están obligadas a implementar sus métodos......... en este caso veremos como la clase Animal al ser abstracta no esta obligada a hacerlo, pero sus hijas si....
Veamos como se codifica el diagrama anterior en Java:
Interface IAnimal.
public interface IAnimal {La Interface IAnimal posee el método comunicarse() el cual es completamente abstracto, evidenciamos que no es necesario indicarlo mediante la palabra abstract...........De la misma forma tenemos el atributo valor el cual (al ser declarado en la interface) se comporta como una Constante, así que nunca va a cambiar (en la entrada sobre Interfaces indicamos el porqué de estas propiedades)....
int valor=5;
/**
* Método Comunicarse, sera implementado por las clases concretas
* que hereden de la clase Animal
*/
public void comunicarse();
}
Clase Abstracta Animal.
public abstract class Animal implements IAnimal {
private String nombre;
/**
* Constructor de la clase Animal
* @param nombre
*/
public Animal (String nombre){
this.nombre=nombre;
System.out.println("Constructor Animal, " +
"nombre del animal : "+this.nombre);
}
/**
* Retorna el valor de nombre
* @return
*/
public String getNombre(){
return nombre;
}
/**
* Metodo Abstracto tipoAnimal, la implementación depende
* de las clases concretas que extiendan la clase Animal
*/
public abstract void tipoAnimal();
}
Como vemos tenemos la clase Abstracta que implementa la Interface IAnimal pero como mencionamos al principio, esta clase no esta obligada a implementar el método comunicarse() ya que también es clase abstracta.
Tenemos el método tipoAnimal() el cual si debe ser declarado como abstracto, evidenciamos también el atributo nombre el cual lo declaramos como private y solo accederemos a el en nuestro árbol de herencia, con el aplicamos un poquito el concepto de Encapsulación (pero no de la forma ideal, podemos ver una pequeña definición en la entrada sobre conceptos Básicos).
Clase Gato.
public class Gato extends Animal{
/**
* Constructor explicito clase Gato
* @param nombre
*/
public Gato(String nombre) {
super(nombre);//envia el parametro a el constructor de la clase padre
System.out.println("Constructor Gato, nombre : "+nombre);
}
public void tipoAnimal() {
System.out.println("Tipo Animal : Es un Gato");
}
public void comunicarse(){
System.out.println("Metodo comunicarse : El gato maulla... Miau Miau");
}
}
Clase Perro.
public class Perro extends Animal{
/**
* @param nombre
*/
public Perro(String nombre) {
super(nombre);
System.out.println("Constructor perro, nombre : "+nombre);
}
public void tipoAnimal() {
System.out.println("Tipo Animal : Es un Perro");
}
public void comunicarse(){
System.out.println("Metodo comunicarse : El perro Ladra... Guau Guau");
}
}
Como vemos las Clases Gato y Perro heredan de la clase abstracta Animal, por ende implementan el método tipoAnimal(), y como Animal implementa la interface IAnimal, entonces tanto Gato como Perro al ser clases concretas están obligadas a implementar el método comunicarse()....
En las clases también podemos ver que se utiliza la propiedad nombre que es enviada al constructor de Animal mediante el llamado a super(nombre).
Hasta aquí ya tenemos las clases del diagrama, ahora veamos como relacionarlas mediante una clase principal.
Clase Test.
public class Test {Esta clase permite la creación de Objetos Polimorficos donde vemos que podemos usar las superClases para crear objetos de sus subClases, de esa forma podemos decir que perro es un Animal o Gato es un Animal .... Al ejecutar obtenemos.
public static void main (String[] arg){
/**Creamos anim, un objeto Perro de tipo Animal*/
Animal anim= new Perro("goliath") ;
anim.tipoAnimal();
anim.comunicarse();
System.out.println();
/**Creamos perro, un objeto Perro de tipo Perro*/
Perro perro=new Perro("hercules");
perro.tipoAnimal();
System.out.println();
/**Creamos animalPolimorfico, un objeto perro de tipo Animal
* asignamos una referencia ya existente*/
Animal animalPolimorfico=perro;
animalPolimorfico.tipoAnimal();
System.out.println();
/**reasignamos la referencia del objeto anim a el objeto perro
* esto es valido ya que ambos son de tipo Perro*/
perro=(Perro) anim;
perro.tipoAnimal();
System.out.println();
/**Creamos gat, un objeto Gato de tipo Animal*/
Animal gat=new Gato("pichi");
gat.tipoAnimal();
gat.comunicarse();
System.out.println();
/**Creamos cat, un objeto Gato de tipo IAnimal
* Para esto aplicamos polimorfismo usando la Interface*/
IAnimal cat = new Gato("pitufa");
cat.comunicarse();
System.out.println("\nConstante en la interfaz Animal : "+IAnimal.valor);
}
}
En este ejemplo creamos diferentes objetos uno a uno para verificar la aplicación del polimorfismo, pero esto también puede evidenciarse de otras maneras, por ejemplo podemos crear un arreglo de tipo Animal y en el almacenar objetos de su árbol de herencia.... veamos..
Agreguemos a la clase Test el siguiente código...
Animal animales[]= { new Perro("simon"),new Perro("paco"),new Gato("mimi")};
for(Animal a : animales){
a.tipoAnimal();
}
System.out.println();
Como mencioné hace un momento, tenemos un arreglo animales de tipo Animal donde en cada posición almacenamos diferentes objetos subClases de Animal, así que cuando recorremos el arreglo podemos acceder a las propiedades del objeto que corresponda, así como las de su superClase...
Si de pronto quisieramos agregar al arreglo animales un objeto de tipo Planta, esto nos arrojaría error, ya que planta no debería hacer parte de la Jerarquía definida para el arreglo con el que estamos trabajando, en otras palabras porque planta no es un Animal....
Conclusiones....
En los ejemplos pudimos aplicar las reglas de Polimorfismo vistas en la entrada anterior además también evidenciamos la aplicación de otros conceptos combinando algunos como la Herencia, Clases Concretas, Clases Abstractas, Interfaces.
Podemos resaltar el método comunicarse() que heredan las clases Perro y Gato, donde al ser un método abstracto nos permite dar la implementación que queramos dependiendo de quien lo use, entonces podemos ver que tanto perro como gato se comunican pero de forma distinta y esa diferencia se ve en nuestra implementación...
En general vimos la importancia de trabajar con un paradigma Orientado a Objetos, pues nos da facilidades tanto a nivel de optimización como a nivel de estructura y lógica de la aplicación, así como brindar claridad en los principales conceptos en torno a la POO...
Mas adelante nos adentraremos en el mundo de los Patrones de Diseño, donde se podrán evidenciar y aplicar los conceptos vistos nuevamente....
También te podría Interesar.
- Conceptos de Polimorfismo en Java
- Interfaces en Java
- Clases Abstractas.
- Herencia en Java.
- ¿ String Vrs StringBuffer Vrs StringBuilder ?
- Comparando Fechas En Java
- Tutorial Aplicaciones Web con Jboss Seam