Clases Abstractas e Interfaces.


Hablar de Herencia y Polimorfismo es desgastante, debido a que hay muchas cosas que explicar, así que para darme tiempo de terminar el post "Herencia y Polimorfismo, parte II" hablare acerca de clases abstractas e interfaces, que son parte importante de la Herencia y el Polimorfismo y son más sencillos de explicar.

Clases Abstractas.

Una clase es definida como abstracta cuando uno o más de sus métodos son declarados como abstractos, es decir no tienen ninguna implementación y la primera clase concreta que herede de esta debe implementar todos sus métodos abstractos. Cabe mencionar que una clase abstracta no puede ser instanciada, sino que su propósito es ser extendida, quizás sea difícil imaginar para que puede servir esto, pero intentaremos descubrirlo con un ejemplo.

Pensemos en los celulares, todos los celulares tienen funciones básicas compartidas, como el llamar, contestar, recibir mensajes y enviar mensajes, así que crearemos una clase abstracta con estas funciones.

package AbstractClassAndInterface;

public abstract class Cellphone
{
 private String myNumber;
 
 public Cellphone(String myNumber)
 {
  this.myNumber = myNumber;
 }
 
 public abstract void on();
 
 public abstract void off();
 
 public void call(String number)
 {
  System.out.println("Call to the number " + number);
 }
 
 public void response(String number)
 {
  System.out.println("Response to number " + number);
 }
 
 public abstract void sendMenssage(String message, String number);
 
 public abstract void readMessage(String message);
 
 public String getNumber()
 {
  return this.myNumber;
 }
}

Hemos creado una clase abstracta, que tiene el comportamiento de los celulares estándar todas las clases que hereden de ella, heredaran los métodos call, response y getNumber que ya han sido implementados, y si la clase es concreta deberá implementar los métodos, on, off, sendMessage, readMessage. Podemos notar que la forma en que declaramos la clase Cellphone incluye la palabra abstract que es la que le indica al compilador que la clase es abstracta, al igual los métodos abstractos ocupan la palabra abstract y terminan en punto y coma, sin tener un cuerpo de método.

Si la que extiende la clase abstracta es otra clase abstracta, entonces puede delegar la implementación de los métodos abstractos a la primera clase concreta que herede de ella, y agregar sus propios métodos tanto abstractos como no abstractos.

package AbstractClassAndInterface;

public abstract class Smartphone extends Cellphone
{
 public Smartphone(String number)
 {
  super(number);
 }
 
 public void on()
 {
  System.out.println("Turn on a smartphone");
 }
 
 public void off()
 {
  System.out.println("Turn off a smartphone");
 }
 
 public abstract void surfWeb(String URL);
}

Hemos creado la clase abstracta Smartphone que extiende de la clase abstracta Cellphone, decidimos aquí implementar los métodos on y off, que como se puede observar ahora tienen un cuerpo de método, han eliminado la palabra abstract y el punto coma, además hemos agregado un método abstracto más llamado surfWeb, ahora pasemos a las clases concretas haremos un Android y un Blackberry.

package AbstractClassAndInterface;

public class Android extends Smartphone
{
 public Android(String number)
 {
  super(number);
 }
 
 public void sendMenssage(String message, String number)
 {
  System.out.println("Android Sending a message to number " + number
   + "\r\n" + message);
 }
 
 public void readMessage(String message)
 {
  System.out.println("Android Reading a message: " + message);
 }
 
 public void surfWeb(String URL)
 {
  System.out.println("Android Surfing on the web: " + URL);
 }
}

package AbstractClassAndInterface;

public class Blackberry extends Smartphone
{
 public Blackberry(String number)
 {
  super(number);
 }
 
 public void sendMenssage(String message, String number)
 {
  System.out.println("Blackberry Sending a message to number " + number
   + "\r\n" + message);
 }
 
 public void readMessage(String message)
 {
  System.out.println("Blackberry Reading a message: " + message);
 }
 
 public void surfWeb(String URL)
 {
  System.out.println("Blackberry Surfing on the web: " + URL);
 }
}

Hemos creado nuestros smartphone's, los cuales implementan finalmente todos los métodos abstractos tanto los de la clase abstracta Cellphone como los de Smartphone, es tiempo de probarlo.

package AbstractClassAndInterface;

public class SmartphoneTestDrive
{
 public static void main(String[] args)
 {
  SmartphoneTestDrive test = new SmartphoneTestDrive();
  test.createCellphones();
 }
 
 public void createCellphones()
 {
  Smartphone android = new Android("2291 23 45 67");
  Smartphone blackberry = new Blackberry("2292 34 56 78");
  
  System.out.println("\r\n----Android: " + android.getNumber());
  useCellphone(android);
  
  System.out.println("\r\n----Blackberry: " + blackberry.getNumber());
  useCellphone(blackberry);
 }
 
 private void useCellphone(Smartphone smartphone)
 {
  String cpNumber = "2299 01 23 45";
  String cpNumber2 = "2290 12 34 56";
  
  smartphone.on();
  smartphone.call(cpNumber);
  smartphone.response(cpNumber2);
  smartphone.sendMenssage("Un mensaje de prueba", cpNumber);
  smartphone.readMessage("Te envie un mensaje lo recibiste?");
  smartphone.surfWeb("www.google.com");
 }
}



Funciona, ahora podemos utilizar cualquier smartphone que herede de la clase abstracta, y ejecutarlo con el método useCellphone, si te preguntas por que funciona tendrás que esperar hasta la segunda parte de herencia y polimorfismo, ya que es parte del polimorfismo.

Interfaces.

Una interfaz es básicamente un contrato, la clase que implementa a una interfaz debe de implementar cada uno de los métodos que en ella se definen, una interfaz no contiene variables solo métodos y constantes (al menos en Java), las constantes siempre deben de ser declaradas como "public static final" por el momento no las ocuparemos, vayamos directo al código.

Queremos mandar un mensaje vía Internet de un smartphone a otro, podemos generar una interfaz genérica que envié un mensaje, pero tenemos un problema, Blackberry ocupa BBM(Blackberry Messenger) y Android ocupa WA(Whats App), podríamos crear dos clases abstractas distintas una para Android y otra para Blackberry, pero eso arruinaría nuestro código de prueba anterior, podríamos implementarlo directamente en las clases pero pueden existir tanto Android's como Blackberry's que no soporten esos servicios, es en este momento cuando se vuelve necesario hacer uso de las interfaces.

package AbstractClassAndInterface;

public class Android extends Smartphone implements WhatsApp
{
 public Android(String number)
 {
  super(number);
 }
 
 public void sendMenssage(String message, String number)
 {
  System.out.println("Android Sending a message to number " + number
   + "\r\n" + message);
 }
 
 public void readMessage(String message)
 {
  System.out.println("Android Reading a message: " + message);
 }
 
 public void surfWeb(String URL)
 {
  System.out.println("Android Surfing on the web: " + URL);
 }
 
 public void sendWhatsAppMessage(String message, String user)
 {
  System.out.println("Android Sending WhatsApp message to user " + user
   + "\r\n" + message);
 }
 
 public void receiveWhatsAppMessage(String Message)
 {
  System.out.println("Android Reading WhatsApp message: " + message);
 }
}

package AbstractClassAndInterface;

public class Blackberry extends Smartphone implements  BlackberryMessenger, WhatsApp
{
 public Blackberry(String number)
 {
  super(number);
 }
 
 public void sendMenssage(String message, String number)
 {
  System.out.println("Blackberry Sending a message to number " + number
   + "\r\n" + message);
 }
 
 public void readMessage(String message)
 {
  System.out.println("Blackberry Reading a message: " + message);
 }
 
 public void surfWeb(String URL)
 {
  System.out.println("Blackberry Surfing on the web: " + URL);
 }
 
 public void sendBlackberryMessenger(String message, String user)
 {
  System.out.println("Blackberry Sending BlackberyMessenger to user " + user
   + "\r\n" + message);
 }
 
 public void receiveBlackberryMessenger(String message)
 {
  System.out.println("Blackberry Reading BlackberyMessenger message: " + message);
 }
 
 public void sendWhatsAppMessage(String message, String user)
 {
  System.out.println("Blackberry Sending WhatsApp message to user " + user
   + "\r\n" + message);
 }
 
 public void receiveWhatsAppMessage(String Message)
 {
  System.out.println("Blackberry Reading WhatsApp message: " + message);
 }
}

Hemos creado nuestras interfaces, cabe mencionar que una interfaz puede implementar de otra, es decir podríamos hacer lo siguiente.

public BlackberryMessenger extends WhatsApp

Es decir quién implemente BlackberryMessenger también debería implementar WhatsApp, pero vayamos a la acción modifiquemos Android y Blackberry para enviar mensajes.


Ahora que hemos implementado las interfaces es hora de hacer una prueba, cabe mencionar que por definición todos los métodos en las interfaces son declarados como "public".

package AbstractClassAndInterface;

public class SmartphoneTestDrive
{
 public static void main(String[] args)
 {
  SmartphoneTestDrive test = new SmartphoneTestDrive();
  test.createCellphones();
 }
 
 public void createCellphones()
 {
  Smartphone android = new Android("2291 23 45 67");
  Smartphone blackberry = new Blackberry("2292 34 56 78");
  
  System.out.println("\r\n----Android: " + android.getNumber());
  useCellphone(android);
  
  System.out.println("\r\n----Blackberry: " + blackberry.getNumber());
  useCellphone(blackberry);
 }
 
 private void useCellphone(Smartphone smartphone)
 {
  String cpNumber = "2299 01 23 45";
  String cpNumber2 = "2290 12 34 56";
  
  smartphone.on();
  smartphone.call(cpNumber);
  smartphone.response(cpNumber2);
  smartphone.sendMenssage("Un mensaje de prueba", cpNumber);
  smartphone.readMessage("Te envie un mensaje lo recibiste?");
  smartphone.surfWeb("www.google.com");
  sendWebMessage("Hello im sending a web message", "some user", smartphone);
  receiveMessage("Hi, i received your message, how are you?", smartphone);
 }
 
 private void sendWebMessage(String message, String user, Smartphone smartphone)
 {
  if(smartphone instanceof WhatsApp)
   ((WhatsApp)smartphone).sendWhatsAppMessage(message, user);
  
  if(smartphone instanceof BlackberryMessenger)
   ((BlackberryMessenger)smartphone).sendBlackberryMessenger(message, user);
 }
 
 private void receiveMessage(String message, Smartphone smartphone)
 {
  if(smartphone instanceof WhatsApp)
   ((WhatsApp)smartphone).receiveWhatsAppMessage(message);
  
  if(smartphone instanceof BlackberryMessenger)
   ((BlackberryMessenger)smartphone).receiveBlackberryMessenger(message);
 }
}



Y básicamente es todo, ahora puedes agregar más funcionalidades si así lo deseas.

Happy Coding...

No hay comentarios:

Publicar un comentario