ODVFODVHVDEVWUDFWDVSXHGHQWHQHURQRLPSOHPHQWDFLRQHVGH ODVFODVHVDEVWUDFWDVSXHGHQWHQHURQRL PSOHPHQWDFLRQHVGHORVPHWRGRVPLH ORVPHWRGRVPLHPEURVGHODFODVH\ PEURVGHODFODVH\ODV ODV LQWHUIDFHVQRWLHQHQQLQJXQDLPSOHPHQWDFLRQ LQWHUIDFHVQRWLHQHQQ LQJXQDLPSOHPHQWDFLRQVRORODVGHFODUDFLRQ VRORODVGHFODUDFLRQHVGHORVPLHPEUR HVGHORVPLHPEURVTXHGHEHQ VTXHGHEHQ FRQVWLWXLUODFODVHTXHLPSOHPHQWHGL FRQVWLWXLUODF ODVHTXHLPSOHPHQWHGLFKDLQWHUID] FKDLQWHUID] ORVPLHPEURVGHODLQWHUID]GHEHQVHUSXEO ORVPLHPEURVGHOD LQWHUID]GHEHQVHUSXEOLFRV\VLQLPSOH LFRV\VLQLPSOHPHQWDFLRQ PHQWDFLRQ &´GLJR interface iMiInterfaz { int Sumar(int Num1, int Num2); int Multiplicar(int Num1, int Num2); }
ODVFODVHVDEVWUDFWDVSXHGHQWHQHUPLHPEURVDEVWUDFWRV\ ODVFODVHVDEVWUDFWDVSXHGHQWHQHUPLHPEUR VDEVWUDFWRV\QRDEVWUDFWRVHVGHF QRDEVWUDFWRVHVGHFLUVREUHFDUJDEOHVHQO LUVREUHFDUJDEOHVHQODV DV FODVHVTXHKHUHGHQGHHOODSHURHQODVLQ FODVHVTXHKHUHGHQGHHO ODSHURHQODVLQWHUIDFHVWRGRVO WHUIDFHVWRGRVORVPLHPEURVVRQLPS RVPLHPEURVVRQLPSOLFLWDPHQWHDEVW OLFLWDPHQWHDEVWUDFWRV\ UDFWRV\ WRGRVORVPLHPEURVGHODLQWHUID]GHEHQV WRGRVORVPLHPEURVG HODLQWHUID]GHEHQVHUUHLPSOHPHQWD HUUHLPSOHPHQWDGRVHQODFODVHTXHG GRVHQODFODVHTXHGHULYHGHHVWD HULYHGHHVWD
&´GLJR abstract class MiClaseAbstracta { public int Suma(int Num1, int Num2) { return Num1 + Num2; } public abstract int Multiplicacion(int Num1, int Num2); }
CLASES ABSTRACTAS Esta no permite crear objetos, se utiliza para que otras clases hereden de ella, "provocando" la reutilización de código, ósea que no se puede instanciar, y se usa únicamente para definir subclases. Una clase es abstracta cuando uno de sus métodos no tiene implementación y se usa cuando queremos definir una abstracción que englobe objetos de varios tipos y queremos hacer uso del polimorfismo. Una de las características más útiles de cualquier lenguaje orientado a objetos es la posibilidad de declarar clases que definen como se utiliza solamente, sin tener que implementar métodos. esto es muy útil cuando la implementación es específica para cada usuario, pero todos los usuarios tienen que utilizar los mismos métodos. EJEMPLO abstract class FiguraGeometrica { abstract void dibujar(); }
¿Qué es un interface? Un interface es una colección colección de declaraciones de métodos (sin definirlos) y también puede incluir constantes. Runnable es un ejemplo de interface en el cual se declara, pero no se run. implemementa, una función miembro run.
public interface Runnable { public abstract void run(); }
Las
clases que implementen (implements) el interface Runnable han de definir obligatoriamente la función run. class Animacion implements Runnable{ //.. public void run(){ //define la función run } }
El
papel del interface es el de describir algunas de las características de una clase. Por ejemplo, el hecho de que una persona sea un futbolista no define su personalidad completa, pero hace que tenga ciertas características que las distinguen de otras. Clases que no están relacionadas pueden implementar el interface Runnable, por ejemplo, una clase que describa una animación, y también puede implementar el interface Runnable una clase que realice un cálculo intensivo.
Diferencias
entre un interface y una clase abstracta
Un interface es simplemente una lista de métodos no implementados, además puede incluir la declaración de constantes. Una clase abstracta puede incluir métodos implementados y no implementados o abstractos, miembros dato constantes y otros no constantes. Ahora bien, la diferencia es mucho más profunda. Imaginemos que Runnable fuese una clase abstracta. Un applet descrito por la clase MiApplet que moviese una figura por su área de trabajo, derivaría a la vez de la clase base Applet (que describe la funcionalidad mínima de un applet que se ejecuta en un navegador) y de la clase Runnable. Pero el lenguaje Java no tiene herencia múltiple. En
el lenguaje Java la clase MiApplet deriva de la clase base Applet e implementa el interface Runnable class MiApplet extends Applet implements Runnable{ //... //define la función run del interface public void run(){
//... } //redefine paint de la clase base Applet public void paint(Graphics g){ //... } //define otras funciones miembro }
Una clase solamente puede derivar extends de una clase base, pero puede implementar varios interfaces. Los nombres de los interfaces se colocan separados por una coma después de la palabra reservada implements. El
lenguaje Java no fuerza por tanto, una relación jerárquica, simplemente permite que clases no relacionadas puedan tener algunas características de su comportamiento similares.
Los interfaces y el polimorfismo En
el lenguaje C++, es posible la herencia múltiple, pero este tipo de herencia presenta dificultades. Por ejemplo, cuando dos clases B y C derivan de una clase base A, y a su vez una clase D deriva de B y C. Este problema es conocido con el nombre de diamante.
En
el lenguaje Java solamente existe la herencia simple, pero las clases pueden implementar interfaces. Vamos a ver en este apartado que la importancia de los interfaces no estriba en resolver los problemas inherentes a la herencia múltiple sin forzar relaciones jerárquicas, sino es el de incrementar el polimorfismo del lenguaje más allá del que proporciona la herencia simple.
Para explicar este aspecto importante y novedoso del lenguaje Java adaptaremos los ejemplos que aparecen en el artículo del Bill Venners "Designing with interfaces" publicado en Java World (www.javaWorld.com) en Diciembre de 1998. Comparemos la herencia simple mediante un ejemplo similar al de la jerarquía de las figuras planas, con los interfaces.
Herencia
simple
polimorfismo: Animal.java, PoliApp.java
Creamos una clase abstracta denominada Animal de la cual deriva las clases Gato y Perro. Ambas clases redefinen la función habla declarada abstracta en la clase base Animal . public abstract class A nimal { public abstract void habla(); } class Perro extends Animal{ public void habla(){ System.out.println("¡Guau!"); } } class Gato extends Animal{ public void habla(){ System.out.println("¡Miau!"); } }
polimorfismo nos permite pasar la referencia a un objeto de la clase Gato a una función hazleHablar que conoce al objeto por su clase base Animal El
public class PoliApp { public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato); } static void hazleHablar( A nimal sujeto){ sujeto.habla(); } }
El
compilador no sabe exactamente que objeto se le pasará a la función hazleHablar en el momento de la ejecución del programa. Si se pasa un
objeto de la clase Gato se imprimirá ¡Miau!, si se pasa un objeto de la clase Perro se imprimirá ¡Guau!. El compilador solamente sabe que se le pasará un objeto de alguna clase derivada de Animal . Por tanto, el compilador no sabe que función habla será llamada en el momento de la ejecución del programa. El
polimorfismo nos ayuda a hacer el programa más flexible, por que en el futuro podemos añadir nuevas clases derivadas de Animal , sin que cambie para nada el método hazleHablar . Como ejercicio, se sugiere al lector añadir la clase Pajaro a la jerarquía, y pasar un objeto de dicha clase a la función hazleHablar para que se imprima ¡pio, pio, pio ..!.
Interfaces
polimorfismo1: Parlanchin.java, Animal.java, Reloj.java, PoliApp.java
Vamos a crear un interface denominado Parlanchin que contenga la declaración de una función denominada habla. public interface Parlanchin { public abstract void habla(); }
Hacemos
que la jerraquía de clases que deriva de Animal implemente el interface Parlanchin public abstract class Animal implements public abstract void habla(); }
Parlanchin {
class Perro extends Animal{ public void habla(){ System.out.println("¡Guau!"); } } class Gato extends Animal{ public void habla(){ System.out.println("¡Miau!"); } }
Ahora veamos otra jerarquía de clases completamente distinta, la que deriva de la clase base Reloj. Una de las clases de dicha jerarquía Cucu implementa el
interface Parlanchin y por tanto, debe de definir obligatoriamente la función habla declarada en dicho interface. public abstract class Reloj { } class Cucu extends Reloj implements Parlanchin { public void habla(){ System.out.println("¡Cucu, cucu, ..!"); } }
Definamos la función hazleHablar de modo que conozca al objeto que se le pasa no por una clase base, sino por el interface Parlanchin. A dicha función le podemos pasar cualquier objeto que implemente el interface Parlanchin, este o no en la misma jerarquía de clases. public class PoliApp { public static void main(String[] args) { Gato gato=new Gato(); hazleHablar(gato); Cucu cucu=new Cucu(); hazleHablar(cucu); } static void hazleHablar( Parlanchin sujeto){ sujeto.habla(); } }
Al ejecutar el programa, veremos que se imprime en la consola ¡Miau!, por que a la función hazleHablar se le pasa un objeto de la clase Gato, y después ¡Cucu, cucu, ..! por que a la función hazleHablar se le pasa un objeto de la clase Cucu. Si solamente hubiese herencia simple, Cucu tendría que derivar de la clase Animal (lo que no es lógico) o bien no se podría pasar a la función hazleHablar . Con interfaces, cualquier clase en cualquier familia puede implementar el interface Parlanchin, y se podrá pasar un objeto de dicha clase a la función hazleHablar . Esta es la razón por la cual los interfaces proporcionan más polimorfismo que el que se puede obtener de una simple jerarquía de clases.
class Circulo extends FiguraGeometrica { void dibujar() { // código para dibujar Circulo } }
La clase abstracta se declara simplemente con el modificador abstract en su declaración. En método abstract no pude ser static, ya que estos no pueden ser redefinidos por las subclases. INTERFAZ Una interfaz define una serie de métodos que debe implementar una clase. es decir, una interfaz es una colección de métodos sin cuerpo, contiene únicamente lo que se denomina signatura del método. Trabajar con interfaces permite abstraernos de la clase que la implementa. una interfaz en java es una colección de métodos abstractos y propiedades. en ellas se especifica qué se debe hacer pero no su implementación. serán las clases que implementen estas interfaces las que describan la logica del comportamiento de los métodos. la clase boolean los valores //boolean// también tienen su tipo asociado //boolean//, aunque en este caso hay menos métodos implementados que para el resto de las clases numéricas.
==== //declaraciones// ==== la primera sentencia creará una variable boolean y la segunda un objeto boolean: boolean b; boolean b;
==== //valores de boolean// ==== boolean.true; boolean.false;
==== //métodos de boolean// ==== boolean b.booleanvalue(); string b.tostring(); boolean b.equals( object obj );
Saludos a todos, en esta nueva aportación quiero compartir con ustedes un tema que cuando se está iniciando en el aprendizaje de la programación orientada a objetos no se encuentra en ningún libro o bien, pocos instructores lo mencionan -debo admitir que cuando impartí la materia de Introducción a la Programación Orientada a Objetos en el Instituto Tecnológico de León ni siquiera lo mencioné- y me refiero a ¿Cuándo y por qué usar clases abstractas o interfaces? El concepto de clases abstractas e interfaces puede ser un poco confuso para los principiantes en la programación orientada a objetos ya que una clase abstracta sin
ninguna implementación se ve cómo una interface, sin embargo existen muchas diferencias y similitudes entre ellas.
¿Qué es una clase abstracta? Una
clase abstracta es una clase que no puede ser instanciada y que debe ser heredada. Una clase puede implementarse en su totalidad, pero lo más habitual es que se implemente parcialmente o no se implemente en absoluto, encapsulando funcionalidad común para clases heredadas. Para información más detallada, vea Clases abstractas.
¿Qué es una Interface? Una
interface describe un grupo de comportamientos relacionados que pueden pertenecer a cualquier clase o estructura. Las interfaces contienen las firmas de métodos, propiedades, eventos o indizadores. La implementación de los miembros se hace en la clase o la estructura que implementa la interfaz. Para información más detallada, veaInterfaces.
Diferencias
y Similitudes
continuación extraigo parte de una tabla del artículo Abstract Class versus Interface en la que se describen las diferencias y similitudes que existen entre las clases abstractas y las interfaces: A
Característica Herencia Múltiple Implementación por defecto
Modificadores de acceso
Núcleo vs Periferia
Campos y Constantes
Interface
Clase abstracta
Una
Una
clase puede heredar tantas interfaces requiera. Una interface no puede proporcionar ningún código de implementación, solo la firma. Una interface no puede tener modificadores de acceso, todas sus firmas son públicas. Las interfaces son usadas para definir las habilidades periféricas de una clase. Un Humano y un Vehiculo pueden implementar una interface IMovible No pueden ser definidas en una interface
clase sólo puede heredar una clase abstracta. Una clase abstracta puede proporcionar la implementación completa o parcial. Los miembros de una clase abstracta pueden tener modificadores de acceso. Una
clase abstracta define el núcleo de una clase y es usada para objetos del mismo tipo.
Una
clase abstracta puede contener campos y constantes.
Recomendaciones para el uso de clases abstractas vs interfaces La opción de diseñar tu funcionalidad cómo una interface o cómo clase abstracta puede ser difícil en algunas ocasiones. Microsoft en su artículo Recommendations for Abstract
Classes vs. Interfaces nos hace las siguientes recomendaciones que trataré de ejemplificar para mostrar las ventajas de seguirlas.
MÚLTIPLES V ERSIONES Si sabe de antemano que va a crear varias versiones del componente, cree una clase abstracta. Las clases abstractas proporcionan un medio fácil y sencillo para crear versiones de los componentes. Al actualiza la clase base, todas las clases heredadas se actualizan automáticamente con el cambio. Por el contrario, las interfaces no se pueden cambiar una vez creadas. Si necesita una nueva versión de una interfaz, deberá crear una totalmente nueva. Ejemplo: Pensemos en el caso de crear el ABC de una base de datos que contiene la tabla Persona, y además dos especializaciones de esta llamadas Cliente y Empleado; también existe la regla de negocio que indica que no puede registrarse a una persona si no es registrada cómo cliente o cómo empleado. Solución con Clases Abstractas: Se debería de crear una clase abstracta llamada Persona y que defina las propiedades comunes entre Empleado y Cliente así como los métodos que implementan los procesos de Alta, Baja, Cambio de la tabla Persona; adicional a esto se deben crear las clases Empleado y Cliente, ambas heredan de Persona. Cada una deberá definir las propiedades que los diferencian y sobrescribir los métodos Alta, Baja y Cambio de la clase padre, en la sobre escritura de los métodos, se tendrá que hacer una llamada al método base correspondiente y agregar la implementación para modificar la tabla correcta. Solución con Interfaces: Se debería de crear una interface llamada IPersona y que defina las firmas de los procesos de Alta, Baja, Cambio; adicional a esto se deben crear las clases Empleado y Cliente, ambas que implementen la interface IPersona. Cada una deberá definir las propiedades y campos comunes tanto comunes como diferentes, ambas también deben codificar la implementación de los métodos Alta, Baja y Cambio que realizarán los procesos en la tabla Persona y en la tabla correspondiente. Conclusión: Cómo se puede ver, utilizando clases abstractas se puede reutilizar mucho código al heredar los campos, propiedades y llamando a los métodos de la clase base; en cambio con interfaces tenemos que re-escribir los campos y propiedades comunes en todas las clases así cómo el código de los métodos. FUNCIONALID A D
CO MÚN
Si la funcionalidad que está creando va a ser útil en una amplia gama de objetos diferentes, utilice una interfaz. Las clases abstractas deben utilizarse principalmente para objetos estrechamente relacionados, mientras que las interfaces son más adecuadas para proporcionar funcionalidad común a clases no relacionadas. Ejemplo: Se tiene el caso de querer implementar diferentes medios de transporte que existen y se han identificado el Autobus, Avión y Barco. ¿Cómo se implementaría con clases abstractas y cómo con interfaces? Solución con Clases Abstractas: Se crearía una clase abstracta llamada Transporte que defina el método abstracto Transportar; Se crearán las clases Autobus, Avion y Barco, todas ellas heredarán de Transporte y deberán realizar la implementación del método abstracto.
Solución con Interfaces: Se debería de crear una interface llamada ITransporte que defina la firma del método Transportar; Se crearán las clases Autobus, Avion y Barco, todas ellas implementarán la interfaz ITransporte. Conclusión: A simple vista se podría decir que ambas soluciones son iguales, ya que las dos le delegan la responsabilidad de implementar el método Transportar a las clases finales Autobus, Avion y Barco, pero la diferencia está en lo siguiente, ¡No existe herencia múltiple! Por lo tanto con la solución de clases abstractas estaremos desperdiciando una oportunidad de heredar de otra clase, pensemos en este caso, podríamos tener una clase padre llamada Avion y las clases hijas Avioneta, AvionComercial, etc., entonces hazte la siguiente pregunta ¿Avioneta y AvionComercial deberían heredar de Avion o de Transporte? En este caso claramente se ve que la mejor opción es utilizar interfaces.
PEQU EÑ A FUNCIONALID A D Si va a diseñar fragmentos pequeños y concisos de funcionalidad, utilice interfaces. Si va a diseñar unidades funcionales grandes, utilice una clase abstracta. Conclusión: Esta recomendación va muy ligada a las dos anteriores, mientras más grande la funcionalidad es más recomendable la reutilización por lo que las clases abstractas son la mejor opción; con funcionalidad pequeña no es recomendable perder la oportunidad de heredar nuestra clase con una clase padre que tenga una funcionalidad grande para reutilizar sus propiedades y métodos por lo que la utilización de interfaces es nuestra mejor opción. FUNCIONALID A D
CO MÚN
Si desea proporcionar funcionalidad común e implementada en todas las implementaciones del componente, utilice una clase abstracta. Las clases abstractas permiten implementar parcialmente una clase, mientras que las interfaces no contienen ninguna implementación para ningún miembro. Conclusión: Siempre que encuentres funcionalidad común entre dos o más clases, busca la manera de utilizar herencia para la reutilización de código (mientras menos escribas mejor).