jueves, 2 de diciembre de 2010

Diferencia entre Clase Abstracta e Interface


Potencial pregunta de entrevista de trabajo. La diferencia puede parecer obvia en el código, pero en términos de funcionalidad existe un traslapo donde tenemos que detenernos por un momento a reflexionar, si es que no lo hemos hecho, por qué debemos usar una opción o la otra.

Lo primero que recordamos de una clase abstracta es que no podemos instanciarla. La clase abstracta se usa como interfaz de las subsecuentes clases que harán conversión hacia arriba ("upcasting"). Podemos describir el upcasting como la acción de declarar una variable de una clase base (abstracta en la mayoría de los casos), pero instanciando una implementación de la misma. Esto da vida al comportamiento polifórmico.

MyAbstract myAbstract = new MyImplementation();

Veamos un ejemplo de una clase abstracta reloj.


public abstract class Watch {

/* Instance variables */

protected int seconds;
protected int minutes;
protected int hours;

/* Constructors */

public Watch() {

}

public Watch(int h, int m, int s) {
hours = h;
minutes = m;
seconds = s;
}

// Must override this method.
abstract public void showTime();

/*Getters and setters for the time components.*/

public int getSeconds() {
return seconds;
}

public void setSeconds(int seconds) {
this.seconds = seconds;
}

public int getMinutes() {
return minutes;
}

public void setMinutes(int minutes) {
this.minutes = minutes;
}

public int getHours() {
return hours;
}

public void setHours(int hours) {
this.hours = hours;
}
}


Y ahora la implementación de un reloj dijital.


public class DigitalWatch extends Watch {

public DigitalWatch(int h, int m, int s) {
super(h,m,s);
}

public void showTime() {
System.out.println(hours +":" + minutes + ":" + seconds);
}

public static void main(String[] args) {
Watch myWatch = new DigitalWatch(5, 30, 20);
myWatch.showTime(); // Prints "5:30:20".
}
}


Si intentamos replicar este diseño con el uso de una interfaz vemos que necesitamos mover el código antes localizado en la clase base Watch en la implementación de DigitalWatch.


public interface WatchI {

public void showTime();

}


public class DigitalWatchI implements WatchI{

protected int seconds;
protected int minutes;
protected int hours;

public void showTime() {
System.out.println(hours +":" + minutes + ":" + seconds);
}

public DigitalWatchI(int h, int m, int s) {
hours = h;
minutes = m;
seconds = s;
}

/*Getters and setters for the time components.*/

public int getSeconds() {
return seconds;
}

public void setSeconds(int seconds) {
this.seconds = seconds;
}

public int getMinutes() {
return minutes;
}

public void setMinutes(int minutes) {
this.minutes = minutes;
}

public int getHours() {
return hours;
}

public void setHours(int hours) {
this.hours = hours;
}

public static void main(String[] args) {
WatchI myWatch = new DigitalWatchI(5, 30, 20);
myWatch.showTime(); // Prints "5:30:20".
}
}


Las interfaces en Java se utilizan primordialmente para separar la interfaz de la implementación en una manera más estricta de como lo hace las clases abstractas. Una interfaz no permite del todo algún nivel de implementación en los métodos. Con la clase abstracta si podemos heredar la implementación de una clase a otra.

En resumen:

Classe Abstracta Interface
Contiene tanto métodos ejecutables como métodos
abstractos.
No tiene código de implementación.
Todos sus métodos son abstractos.
Una clase solo puede extender de una única clase abstracta. Una clase puede implementar n número de interfaces.
Puede tener variables de instancia, constructores y cualquiera de los tipos de visibildiad: public, private, protected, ninguno (aka package). No puede tener variables de instancia o constructores y solo puede tener métodos públicos o package.

17 comentarios:

  1. Como regla general, si un grupo de clases tienen funcionalidad en comun, se puede crear una clase base y en caso que se necesite encapsular algun aspecto del funcionamiento de la clase, pero el cual no es generico, se hace abstracta.

    La interfaces, se hacen para describir un contracto o aspecto que debe tener una clase para ser X cosa.

    Por ejemplo, us puede tener una interface que defina el funcionamiento basico de un carro, frenar, arrancar, acelerar, etc, pero solo define el funcionamiento, inclusive podria ser mas granular y dividir ese funcionamiento por aspectos logicos del automovil y cada uno seria una interface, despues hacer una clase abstracta llamada carro, que implemente todas esas interface que debe tener un carro, pero tenga programados solo los metodos genericos o basicos :) Y de ahi crear las especificaciones, digase Audi, Toyota, etc.

    ResponderEliminar
    Respuestas
    1. Contratado! con un sueldo de mierda eso si

      Eliminar
    2. Desgraciado jajajaja

      Eliminar
  2. gracias por el articulo, y gracias jsanca por la explicacion.

    ResponderEliminar
  3. muy bueno me sirvio para mi taREA

    ResponderEliminar
  4. Te felicito, muy claro y bien redactado. Me toco que mi hicieran esta pregunta pero no supe contestarla correctamente, si me la vuelven a preguntar no se me olvidara.

    ResponderEliminar
  5. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
    Respuestas
    1. Excelente aporte. Muy bueno para repasar más las relaciones entre clases abstractas, interfaces y polimorfismo (el pan de cada día en POO).

      Eliminar
  6. muchas gracias por el artículo, realmente existe mucha confusión sobre esos dos conceptos. MUCHAS GRACIASSS.

    ResponderEliminar
  7. amigo gracias por su articulo. me sirvio de mucho. tengo una pregunta ¿en las clases abstractas siempre abra herencia ?

    ResponderEliminar
    Respuestas
    1. Siendo abstracta implica que no se puede instanciar directamente, sino por medio de otra clase que herede de ella. Así que se podría decir que sí. Siempre habrá herencia.

      Eliminar
  8. Hombre gracias, igual que a los demás lectores, me has aclarado estos conceptos.

    ResponderEliminar
  9. Todo esto esta un poco desfasado con java 8 y 9 las interfaz han cambiado bastante.

    ResponderEliminar