Sei sulla pagina 1di 31

4.2 Clases abstractas: definicin, mtodos abstractos, implementacin de clases abstractas, modelado de clases abstractas.

Clases abstractas
Concepto
Hay ocasiones, cuando se desarrolla una jerarqua de clases en que algn comportamiento est presente en todas ellas pero se materializa de forma distinta para cada una. Por ejemplo, pensemos en una estructura de clases para manipular figuras geomtricas. Podramos pensar en tener una clase genrica, que podra llamarse FiguraGeometrica y una serie de clases que extienden a la anterior que podran ser Circulo, Poligono, etc. Podra haber un mtodo dibujar dado que sobre todas las figuras puede llevarse a cabo esta accin, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la accin dibujar no tiene sentido para la clase genrica FiguraGeometrica, porque esta clase representa una abstraccin del conjunto de figuras posibles. Para resolver esta problemtica Java proporciona las clases y mtodos abstractos. Un mtodo abstracto es un mtodo declarado en una clase para el cual esa clase no proporciona la implementacin (el cdigo). Una clase abstracta es una clase que tiene al menos un mtodo abstracto. Una clase que extiende a una clase abstracta debe implementar los mtodos abstractos (escribir el cdigo) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte tambin en clase abstracta.

Declaracin e implementacin de mtodos abstractos


Siguiendo con el ejemplo del apartado anterior, se puede escribir: abstract class FiguraGeometrica { . . . abstract void dibujar(); . . . } class Circulo extends FiguraGeometrica { . . . void dibujar() { // codigo para dibujar Circulo . . . } }

La clase abstracta se declara simplemente con el modificador abstract en su declaracin. Los mtodos abstractos se declaran tambin con el mismo modificador, declarando el mtodo pero sin implementarlo (sin el bloque de cdigo encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los mtodos abstractos de la clase base (en el ejemplo el mtodo dibujar) el compilador genera un error indicando que no se han implementado todos los mtodos abstractos y que, o bien, se implementan, o bien se declara la clase abstracta.

Referencias y objetos abstractos


Se pueden crear referencias a clases abstractas como cualquier otra. No hay ningn problema en poner: FiguraGeometrica figura; Sin embargo una clase abstracta no se puede instanciar, es decir, no se pueden crear objetos de una clase abstracta. El compilador producir un error si se intenta: FiguraGeometrica figura = new FiguraGeometrica(); Esto es coherente dado que una clase abstracta no tiene completa su implementacin y encaja bien con la idea de que algo abstracto no puede materializarse. Sin embargo utilizando el up-casting visto en el captulo dedicado a la Herencia si se puede escribir: FiguraGeometrica figura = new Circulo(. . .); figura.dibujar(); La invocacin al mtodo dibujarse resolver en tiempo de ejecucin y la JVM llamar al mtodo de la clase adecuada. En nuestro ejemplo se llamar al mtodo dibujarde la clase Circulo

Clases Abstractas. Al ser utilizado Herencias ("Inheritance") y/o Polimorfismo es muy comn que en la Clase Base existan mtodos diseados nicamente con el propsito de ofrecer una guia para las Clases heredadas, en Java existe un vocablo que permite prohibir el uso de mtodos en Clases Base, este calificativo es : abstract.Al ser definido un mtodo como abstract se restringe que ste sea

llamado directamente, cuando una Clase contiene un mtodo de este tipo a sta se le llama: Clase Abstracta. Al ser definida una Clase, adems de ser declarados los mtodos/campos como abstract tambin es necesario utilizar el vocablo abstract en la definicin de cada Clase.

Clases Abstractas . Una de las caractersticas de las Clases que Heredan("Inherit") de una Clase abstracta, es que stas deben definir los mismos mtodos definidos en la Clase Base; en Java existe otro mecanismo que permite llevar acabo diseos donde se parte de una Estructura o Cpsula. En base a su ambiente, abra un Editor de Textos para generar el siguiente ejemplo.

Cdigo Fuente Musica2.java

import java.util.*; abstract class Instrumento { public abstract void tocar(); public String tipo() { return "Instrumento"; } public abstract void afinar(); } class Guitarra extends Instrumento { public void tocar() { System.out.println("Guitarra.tocar()"); } public String tipo() { return "Guitarra"; }

public void afinar() {} } class Piano extends Instrumento { public void tocar() { System.out.println("Piano.tocar()"); } public String tipo() { return "Piano"; } public void afinar() {} } class Saxofon extends Instrumento { public void tocar() { System.out.println("Saxofon.tocar()"); } public String tipo() { return "Saxofon"; } public void afinar() {} } // Un tipo de Guitarra class Guzla extends Guitarra { public void tocar() { System.out.println("Guzla.tocar()"); } public void afinar() { System.out.println("Guzla.afinar()"); } } // Un tipo de Guitarra class Ukelele extends Guitarra {

public void tocar() { System.out.println("Ukelele.tocar()"); } public String tipo() { return "Ukelele"; } } public class Musica2 { // No importa el tipo de Instrumento, // seguir funcionando debido a Polimorfismo: static void afinar(Instrumento i) { // ... i.tocar(); } static void afinarTodo(Instrumento[] e) { for(int i = 0; i < e.length; i++) afinar(e[i]); }

public static void main(String[] args) { // Declarar un Arreglo SIN INSTANCIAS es valido en Clases Abstractas Instrumento[] orquesta = new Instrumento[5]; // Generar una INSTANCIA de una la Clase Abstracta no es valido // Instrumento nuevo = new Instrumento(); int i = 0; // Up-casting al asignarse el Arreglo

orquesta[i++] = new Guitarra(); orquesta[i++] = new Piano(); orquesta[i++] = new Saxofon(); orquesta[i++] = new Guzla(); orquesta[i++] = new Ukelele(); afinarTodo(orquesta); } }

Clase Musica2 La Clase anterior es idntica aquella definida en el ejemplo de Polimorfismo, sin embargo, la Clase Base de Instrumento fue definida como abstract, algunos detalles de esta definicin :

Ntese que los mtodos definidos como abstract no contienen ningn tipo de cdigo dentro de ellos, inclusive no declaran ni llaves ({ }).

Cuando es definido ms de un mtodo como abstract, es necesario que la Clase como tal sea definida tambin como abstract.

La caracterstica de hacer una Clase/Mtodo abstract reside en que no puede ser generada una instancia de la misma, este comportamiento se demuestra en el mtodo principal (main)

Aunque dentro del mtodo sea generado un Arreglo de esta Clase abstracta, recuerde que un arreglo es nicamente un contenedor de Objetos, esto permite que sea generado sin ningn error.

Dentro de comentarios se encuentra la generacin de una instancia del tipo Instrumento la cual generara un error al ser compilada la Clase.

4.3 Interfaces: definicin, implementacin de interfaces, herencia de interfaces.

INTERFACES A. Introduccin Las interfaces Java son expresiones puras de diseo. Se trata de autnticas conceptualizaciones no implementadas que sirven de gua para definir un determinado concepto (clase) y lo que debe hacer, pero sin desarrollar un mecanismo de solucin. Se trata de declarar mtodos abstractos y constantes que posteriormente puedan ser implementados de diferentes maneras segn las necesidades de un programa. Por ejemplo una misma interfaz podra ser implementada en una versin de prueba de manera poco ptima, y ser acelerada convenientemente en la versin definitiva tras conocer ms a fondo el problema. B. Declaracin Para declarar una interfaz se utiliza la sentencia interface, de la misma manera que se usa la sentencia class: interface MiInterfaz {

int CONSTANTE = 100;

int metodoAbstracto( int parametro );

Se observa en la declaracin que las variables adoptan la declaracin en maysculas, pues en realidad actuarn como constantes final. En ningn caso estas variables actuarn como variables de instancia.

Por su parte, los mtodos tras su declaracin presentan un punto y coma, en lugar de su cuerpo entre llaves. Son mtodos abstractos, por tanto, mtodos sin implementacin C. Implementacin de una interfaz Como ya se ha visto, las interfaces carecen de funcionalidad por no estar implementados sus mtodos, por lo que se necesita algn mecanismo para dar cuerpo a sus mtodos. La palabra reservada implements utilizada en la declaracin de una clase indica que la clase implementa la interfaz, es decir, que asume las constantes de la interfaz, y codifica sus mtodos: class ImplementaInterfaz implements MiInterfaz{

int multiplicando=CONSTANTE;

int metodoAbstracto( int parametro ){

return ( parametro * multiplicando );

En este ejemplo se observa que han de codificarse todos los mtodos que determina la interfaz (metodoAbstracto()), y la validez de las constantes (CONSTANTE) que define la interfaz durante toda la declaracin de la clase. Una interfaz no puede implementar otra interfaz, aunque s extenderla (extends) amplindola. D. Herencia mltiple

Java es un lenguaje que incorpora herencia simple de implementacin pero que puede aportar herencia mltiple de interfaz. Esto posibilita la herencia mltiple en el diseo de los programas Java. Una interfaz puede heredar de ms de una interfaz antecesora. interface InterfazMultiple extends Interfaz1,Interfaz2{ } Una clase no puede tener ms que una clase antecesora, pero puede implementar ms de una interfaz: class MiClase extends SuPadre implements Interfaz1,Interfaz2{ } El ejemplo tpico de herencia mltiple es el que se presenta con la herencia en diamante:

Imagen 6: Ejemplo de herencia mltiple Para poder llevar a cabo un esquema como el anterior en Java es necesario que las clases A, B y C de la figura sean interfaces, y que la clase D sea una clase (que recibe la herencia mltiple): interface A{ } interface B extends A{ } interface C extends A{ } class D implements B,C{ } E. Colisiones en la herencia mltiple En una herencia mltiple, los identificadores de algunos mtodos o atributos pueden coincidir en la clase que hereda, si dos de las interfaces padres tienen algn mtodo o atributo que coincida en nombre. A esto se le llama colisin.

Esto se dar cuando las clases padre (en el ejemplo anterior B y C) tienen un atributo o mtodo que se llame igual. Java resuelve el problema estableciendo una serie de reglas. Para la colisin de nombres de atributos, se obliga a especificar a qu interfaz base pertenecen al utilizarlos. Para la colisin de nombres en mtodos:

Si tienen el mismo nombre y diferentes parmetros: se produce sobrecarga de mtodos permitiendo que existan varias maneras de llamar al mismo. Si slo cambia el valor devuelto: se da un error de compilacin, indicando que no se pueden implementar los dos. Si coinciden en su declaracin: se elimina uno de los dos, con lo que slo queda uno.

F. Envolturas de los tipos simples Los tipos de datos de Java no forman parte de la jerarqua de objetos. Sin embargo a veces es necesario crear una representacin como objeto de alguno de los tipos de datos simples de Java. La API de Java contiene un conjunto de interfaces especiales para modificar el comportamiento de los tipos de datos simple. A estas interfaces se las conoce como envolturas de tipo simple. Todas ellas son hijas de la clase abstracta Number y son:

Double: Da soporte al tipo double. Float: Da soporte al tipo float. Integer: Da soporte a los tipos int, short y byte. Long: Da soporte al tipo long. Character: Envoltura del tipo char. Boolean: Envoltorio al tipo boolean.

********************************************************************
Los mtodos abstractos son tiles cuando se quiere que cada implementacin de la clase parezca y funcione igual, pero necesita que se cree una nueva clase para utilizar los mtodos abstractos. Los interfaces proporcionan un mecanismo para abstraer los mtodos a un nivel superior, lo que permite simular la herencia mltiple de otros lenguajes. Un interfaz sublima el concepto de clase abstracta hasta su grado ms alto. Un interfaz podr verse simplemente como una forma, es como un molde, solamente permite declarar nombres de mtodos, listas de argumentos, tipos de retorno y adicionalmente miembros datos (los cuales podrn ser nicamente tipos bsicos y sern tomados como constantes en tiempo de compilacin, es decir, static y final).

Un interfaz contiene una coleccin de mtodos que se implementan en otro lugar. Los mtodos de una clase son public, static y final. La principal diferencia entre interface y abstract es que un interfaz proporciona un mecanismo de encapsulacin de los protocolos de los mtodos sin forzar al usuario a utilizar la herencia. Por ejemplo:

public interface VideoClip { // comienza la reproduccion del video void play(); // reproduce el clip en un bucle void bucle(); // detiene la reproduccion void stop(); }
Las clases que quieran utilizar el interfaz VideoClip utilizarn la palabra implements y proporcionarn el cdigo necesario para implementar los mtodos que se han definido para el interfaz:

class MiClase implements VideoClip { void play() { <cdigo> } void bucle() { <cdigo> } void stop() { <cdigo> }
Al utilizar implements para el interface es como si se hiciese una accin de copiar-ypegar del cdigo del interface, con lo cual no se hereda nada, solamente se pueden usar los mtodos. La ventaja principal del uso de interfaces es que una clase interface puede ser implementada por cualquier nmero de clases, permitiendo a cada clase compartir el interfaz de programacin sin tener que ser consciente de la implementacin que hagan las otras clases que implementen el interface.

class MiOtraClase implements VideoClip { void play() { <cdigo nuevo> } void bucle() { <cdigo nuevo> } void stop() { <cdigo nuevo> }
Es decir, el aspecto ms importante del uso de interfaces es que mltiples objetos de clases diferentes pueden ser tratados como si fuesen de un mismo tipo comn, donde este tipo viene indicado por el nombre del interfaz. Aunque se puede considerar el nombre del interfaz como un tipo de prototipo de referencia a objetos, no se pueden instanciar objetos en s del tipo interfaz. La definicin de un interfaz no tiene constructor, por lo que no es posible invocar el operador new sobre un tipo interfaz. Un interfaz puede heredar de varios interfaces sin ningn problema. Sin embargo, una clase solamente puede heredar de una clase base, pero puede implementar varios interfaces. Tambin, el JDK ofrece la posibilidad de definir un interfaz vaco, como es el caso de Serialize, que permite serializar un objeto. Un interfaz vaco se puede utilizar como un flag, un marcador para marcar a una clase con una propiedad determinada. La aplicacin java514.java, ilustra algunos de los conceptos referentes a los interfaces. Se definen dos interfaces, en uno de ellos se definen dos constantes y en el otro se declara un mtodo put() y un mtodo get(). Las constantes y los mtodos se podran haber colocado en la misma definicin del interfaz, pero se han separado para mostrar que una clase simple puede implementar dos o ms interfaces utilizando el separador coma (,) en la lista de interfaces. Tambin se definen dos clases, implementando cada una de ellas los dos interfaces. Esto significa que cada clase define el mtodo put() y el mtodo get(), declarados en un interfaz y hace uso de las constantes definidas en el otro interfaz. Estas clase se encuentran en ficheros separados por exigencias del compilador, los ficheros son Constantes.java y MiInterfaz.java, y el contenido de ambos ficheros es el que se muestra a continuacin:

public interface Constantes { public final double pi = 6.14; public final int constanteInt = 125;

} public interface MiInterfaz { void put( int dato ); int get(); }


Es importante observar que en la definicin de los dos mtodos del interfaz, cada clase los define de la forma ms adecuada para esa clase, sin tener en cuenta cmo estar definidos en las otras clases. Una de las clases tambin define el mtodo show(), que no est declarado en el interfaz. Este mtodo se utiliza para demostrar que un mtodo que no est declarado en el interfaz no puede ser accedido utilizando una variable referencia de tipo interfaz. El mtodo main() en la clase principal ejecuta una serie de instanciaciones, invocaciones de mtodos y asignaciones destinadas a mostrar las caractersticas de los interfaces descritos anteriormente. Si se ejecuta la aplicacin, las sentencias que se van imprimiendo en pantalla son autoexplicactivas de lo que est sucediendo en el corazn de la aplicacin. Los interfaces son tiles para recoger las similitudes entre clase no relacionadas, forzando una relacin entre ellas. Tambin para declarar mtodos que forzosamente una o ms clases han de implementar. Y tambin, para tener acceso a un objeto, para permitir el uso de un objeto sin revelar su clase, son los llamados objetos annimos, que son muy tiles cuando se vende un paquete de clases a otros desarrolladores. C++ permite al programador crear nuevas clases como una subclase de dos o ms superclases diferentes, es la herencia mltiple. Java no permite herencia mltiple. Hay autores que dicen que el interfaz de Java es un sustituto de la herencia mltiple y hay otros que estn en desacuerdo con eso. Lo cierto es que s parece una alternativa y los interfaces resuelven algunos de los problemas de la herencia mltiple, por ejemplo: No se pueden heredar variables desde un interfaz No se pueden heredar implementaciones de mtodos desde un interfaz La jerarqua de un interfaz es independiente de la jerarqua de clases que implementen el mismo interfaz y esto no es cierto en la herencia mltiple, tal como se ve desde C++.

Definicin
La definicin de un interfaz es semejante a la de una clase. La definicin de interfaz tiene dos componentes, declaracin y cuerpo. En forma esquemtica sera:

DeclaracionInterfaz {

// cuerpoInterfaz }

Declaracin
La mnima declaracin consiste en la palabra clave interface y el nombre del interfaz. Por convenio, los nombres de interfaces comienzan con una letra mayscula, como los nombres de las clases, pero no es obligatorio. La declaracin de interfaz puede tener dos componentes adicionales, el especificador de acceso public y la lista de superinterfaces. Un interfaz puede extender otros interfaces. Sin embargo, mientras que una clase solamente puede extender otra clase, un interfaz puede extender cualquier nmero de interfaces. En el ejemplo se muestra la definicin completa de un interfaz, declaracin y cuerpo.

public interface MiInterfaz extends InterfazA,InterfazB { public final double PI = 3.14159; public final int entero = 125; void put( int dato ); int get(); }
El especificador de acceso public indica que el interfaz puede ser utilizado por cualquier clase de cualquier paquete. Si se omite, el interfaz solamente ser accesible a aquellas clases que estn definidas en el mismo paquete. La clusula extends es similar a la de la declaracin de clase, aunque un interfaz puede extender mltiples interfaces. Un interfaz no puede extender clases. La lista de superinterfaces es un lista separada por comas de todas las interfaces que la nueva interfaz va a extender. Un interfaz hereda todas las constantes y mtodos de sus superinterfaces, excepto si el interfaz oculta una constante con otra del mismo nombre, o si redeclara un mtodo con una nueva declaracin de ese mtodo. El cuerpo del interfaz contiene las declaraciones de los mtodos, que terminan en un punto y coma y no contienen cdigo alguno en su cuerpo. Esto es semejante al prototipo de funciones en C++. Todos los mtodos declarados en un interfaz son implcitamente, public y abstract, y no se permite el uso de transient, volatile, private, protected o syncronized en la declaracin de miembros en un interfaz. En el cuerpo del interfaz se pueden definir constantes, que sern implcitamente public, static y final.

Implementacin
Un interfaz se utiliza definiendo una clase que implemente el interfaz a travs de su nombre. Cuando una clase implementa un interfaz, debe proporcionar la definicin completa de todos los mtodos declarados en el interfaz y, tambin, la de todos los mtodos declarados en todos los superinterfaces de ese interfaz. Una clase puede implementar ms de un interfaz, incluyendo varios nombre de interfaces separados por comas. En este caso, la clase debe proporcionar la definicin completa de todos los mtodos declarados en todos los interfaces de la lista y de todos los superinterfaces de esos interfaces. En el anterior ejemplo, java514.java, se puede observar una clase que implementa dos interfaces, Constantes y MiInterfaz.

class ClaseA implements Constantes,MiInterfaz { double dDato; // Define las versiones de put() y get() que utiliza la ClaseA public void put( int dato ) { // Se usa "pi" del interfaz Constantes dDato = (double)dato * pi; System.out.println( "En put() de ClaseA, usando pi del interfaz " + "Constantes: " + dDato ); } public int get() { return( (int)dDato ); } // Se define un metodo show() para la ClaseA que no esta // declarado en el interfaz MiInterfaz void show() { System.out.println( "En show() de ClaseA, dDato = " + dDato ); }

}
Como se puede observar, esta clase proporciona la definicin completa de los mtodos put() y get() del interfaz MiInterfaz, a la vez que utiliza las constantes definidas en el interfaz Constantes. Adems, la clase proporciona la definicin del mtodo show() que no est declarado en ninguno de los interfaces, sino que es propio de la clase. La definicin de un interfaz es una definicin de un nuevo tipo de datos. Se puede utilizar el nombre del interfaz en cualquier lugar en que se pueda utilizar un nombre de tipo de dato. Sin embargo, no se pueden instanciar objetos del tipo interfaz, porque un interfaz no tiene constructor. En esta seccin, hay numerosos ejemplos de uso del nombre de un interfaz como tipo.

Herencia "Multiple"
Un interfaz no es solamente una forma ms pura de denominar a una clase abstracta, su propsito es mucho ms amplio que eso. Como un interfaz no tiene ninguna implementacin, es decir, no hay ningun tipo de almacenamiento asociado al interfaz, no hay nada que impida la combinacin de varios interfaces. Esto tiene mucho valor porque hay veces en que es necesario que un objeto X sea a y b y c. En C++ es donde esto se acu como herencia multiple y no es sencillo de hacer porque cada clase puede tener su propia implementacin. En Java, se puede hacer lo mismo, pero solamente una de las clases puede tener implementeacin, con lo cual los problemas que se presentan en C++ no suceden con Java cuando se combinan multiples interfaces. En una clase derivada, el programador no est forzado a tener una clase base sea esta abstracta o concreta, es decir, una sin mtodos abstractos. Si se hereda desde una clase no interfaz, solamente se puede heredar de una. El resto de los elementos base deben ser interfaces. Todos los nombres de interfaces se colocan despus de la palabra clave implements y separados por comas. Se pueden tener tantos interfaces como se quiera y cada uno de ellos ser un tipo independiente. El ejemplo siguiente, java516.java, muestra una clase concreta combinada con varios interfaces para producir una nueva clase

import java.util.*; interface Luchar { void luchar(); } interface Nadar { void nadar(); } interface Volar { void volar();

} class Accion { public void luchar() {} } class Heroe extends Accion implements Luchar,Nadar,Volar { public void nadar() {} public void volar() {} } public class java516 { static void a( Luchar x ) { x.luchar(); } static void b( Nadar x ) { x.nadar(); } static void c( Volar x ) { x.volar(); } static void d( Accion x ) { x.luchar(); } public static void main( String args[] ) { Heroe i = new Heroe(); a( i ); // Trata al Heroe como Luchar b( i ); // Trata al Heroe como Nadar c( i ); // Trata al Heroe como Volar d( i ); // Trata al Heroe como Accion

} }
Se puede observar que Heroe combina la clase concreta Accion con los interfaces Luchar, Nadar y Volar. Cuando se combina la clase concreta con interfaces de este modo, la clase debe ir la primera y luego los interfaces; en caso contrario, el compilador dar un error. La autentificacin, signature, para luchar() es la misma en el interfaz Luchar y en la clase Accion, y luchar() no est proporcionado con la definicion de Heroe. Si se quiere crear un objeto del nuevo tipo, la clase debe tener todas las definiciones que necesita, y aunque Heroe no proporciona una definicion explicita para luchar(), la definicin es proporcionada automticamente por Accion y as es posible crear objetos de tipo Heroe. En la clase java516, hay cuatro mtodos que toman como argumentos los distintos interfaces y la clase concreta. Cuando un objeto Heroe es creado, puede ser pasado a cualquierea de estos mtodos, lo que significa que se est realizando un upcasting al interfaz de que se trate. Debido a la forma en que han sido diseados los interfaces en Java, esto funciona perfectamente sin ninguna dificultad ni esfuerzo extra por parte del programador. La razn principal de la existencia de los interfaces en el ejemplo anterior es el proder realizar un upcasting a ms de un tipo base. Sin embargo, hay una segunda razn que es la misma por la que se usan clases abstractas: evitar que el programador cliente tenga que crear un objeto de esta clase y establecer que solamente es un interfaz. Y esto plantea la cuestin de qu se debe utilizar pues, un interfaz o una clase abastacta. Un interfaz proporciona los beneficios de una clase abstracta y, adems, los beneficios propios del interfaz, as que es posible crear una clase base sin la definicin de ningn mtodo o variable miembro, por lo que se deberan utilizar mejor los interfaces que las clases abstractas. De hecho, si se desea tener una clase base, la primera eleccin debera ser un interfaz, y utilizar clases abstractas solamente si es necesario tener alguna variable miembro o algun mtodo implementado.

4.4 Variables polimrficas (plantillas): definicin, uso y aplicaciones.


Variables polimrficas En Java, las variables que contienen objetos son variables polimrficas. El trmino polimrfico (literalmente: muchas formas) se refiere al hecho de que una misma variable puede contener objetos de diferentes tipos (del tipo declarado o de cualquier subtipo del tipo declarado). El polimorfismo aparece en los lenguajes orientados a objetos en numerosos contextos, las variables polimrficas constituyen justamente un primer ejemplo. Observemos la manera en que el uso de una variable polimrfica nos ayuda a simplificar nuestro mtodo listar. El cuerpo de este mtodo es for (Elemento elemento : elementos) elemento.imprimir(); En este mtodo recorremos la lista de elementos (contenida en un ArrayList mediante la variable elementos), tomamos cada elemento de la lista y luego invocamos su mtodo imprimir. Observe que los elementos que tomamos de la lista son de tipo CD o DVD pero no son de tipo Elemento. Sin embargo, podemos asignarlos a la variable elemento (declarada de tipo Elemento) porque son variables polimrficas. La variable

elemento es capaz de contener tanto objetos CD como objetos DVD porque estos son subtipos de Elemento. Por lo tanto, el uso de herencia en este ejemplo ha eliminado la necesidad de escribir dos ciclos en el mtodo listar. La herencia evita la duplicacin de cdigo no slo en las clases servidoras sino tambin en las clases clientes de aquellas. Nota: Si UD. codifica lo que estamos detallando descubrir que el mtodo imprimir tiene un problema: no imprime todos los detalles. Esto es as porque estamos invocando el mtodo imprimir() de la clase Elemento, que no imprime atributos de CD o DVD.

Enmascaramiento de tipos (Casting)


Algunas veces, la regla de que no puede asignarse un supertipo a un subtipo es ms restrictiva de lo necesario. Si sabemos que la variable de un cierto supertipo contiene un objeto de un subtipo, podra realmente permitirse la asignacin. Por ejemplo: Vehiculo v; Coche a = new Coche(); v = a; // Sin problemas a = v; // Error, segn el compilador Obtendremos un error de compilacin en a = v. El compilador no acepta esta asignacin porque como a (Coche) tiene mas atributos que v (Vehculo) partes del objeto a quedan sin asignacin. El compilador no sabe que v ha sido anteriormente asignado por un coche. Podemos resolver este problema diciendo explcitamente al sistema, que la variable v contiene un objeto Coche, y lo hacemos utilizando el operador de enmascaramiento de tipos, en una operacin tambin conocida como casting. a = (Coche)v; // correcto En tiempo de ejecucin, el Java verificar si realmente v es un Coche. Si fuimos cuidadosos, todo estar bien; si el objeto almacenado en v es de otro tipo, el sistema indicar un error en tiempo de ejecucin (denominado ClassCastException) y el programa se detendr. El compilador no detecta (Naturalmente) errores de enmascaramiento en tiempo de compilacin. Se detectan en ejecucin y esto no es bueno. El enmascaramiento debiera evitarse siempre que sea posible, porque puede llevar a errores en tiempo de ejecucin y esto es algo que claramente no queremos. El compilador no puede ayudamos a asegurar la correccin de este caso. En la prctica, raramente se necesita del enmascaramiento en un programa orientado a objetos bien estructurado. En la mayora de los casos, cuando se use un enmascaramiento en el cdigo, debiera reestructurarse el cdigo para evitar el enmascaramiento, y se terminar con un programa mejor diseado. Generalmente, se resuelve el problema de la presencia de un enmascaramiento reemplazndolo por un mtodo polimrfico (Un poquito de paciencia).

La clase Object
Todas las clases tienen una superclase. Hasta ahora, nos puede haber parecido que la mayora de las clases con que hemos trabajado no tienen una superclase, excepto clases como DVD y CD que extienden otra clase. En realidad, mientras que podemos declarar una superclase explcita para una clase dada, todas las clases que no tienen una declaracin explcita de superclase derivan implcitamente de una clase de nombre Object. Object es una clase de la biblioteca estndar de Java que sirve como superclase para todos los objetos. Es la nica clase de Java sin superclase. Escribir una declaracin de clase como la siguiente public class Person{} es equivalente a public class Person extends Object{}
Tener una superclase sirve a dos

propsitos.

. Podemos declarar variables polimrficas de tipo Object que pueden contener cualquier objeto (esto no es importante) . Podemos usar Polimorfismo (Ya lo vemos) y esto si es importante.

Autoboxing y clases envoltorio


Hemos visto que, con una parametrizacin adecuada, las colecciones pueden almacenar objetos de cualquier tipo; queda un problema, Java tiene algunos tipos que no son objetos. Como sabemos, los tipos primitivos tales como int, boolean y char estn separados de los tipos objeto. Sus valores no son instancias de clases y no derivan de la clase Object. Debido a esto, no son suptipos de Object y normalmente, no es posible ubicarlos dentro de una coleccin. Este es un inconveniente pues existen situaciones en las que quisiramos crear, por ejemplo, una lista de enteros (int) o un conjunto de caracteres (char). Qu hacer? La solucin de Java para este problema son las clases envoltorio. En Java, cada tipo simple o primitivo tiene su correspondiente clase envoltorio que representa el mismo tipo pero que, en realidad, es un tipo objeto. Por ejemplo, la clase envoltorio para el tipo simple int es la clase de nombre Integer. La siguiente sentencia envuelve explcitamente el valor de la variable ix de tipo primitivo int, en un objeto Integer: Integer ienvuelto = new Integer(ix); y ahora ienvuelto puede almacenarse fcilmente por ejemplo, en una coleccin de tipo ArrayList<Integer>. Sin embargo, el almacenamiento de valores primitivos en un objeto coleccin se lleva a cabo an ms fcilmente mediante una caracterstica del compilador conocida como autoboxing. En cualquier lugar en el que se use un valor de un tipo primitivo en un contexto que requiere un tipo objeto, el compilador automticamente envuelve al valor de tipo primitivo en un objeto con el envoltorio adecuado. Esto quiere decir que los valores de tipos primitivos se pueden agregar directamente a una coleccin: private ArrayList<Integer> listaDeMarcas; public void almacenarMarcaEnLista (int marca){ listaDeMarcas.agregar(marca); } La operacin inversa, unboxing, tambin se lleva a cabo automticamente, de modo que el acceso a un elemento de una coleccin podra ser: int primerMarca = listaDeMarcas.remove(0); El proceso de autoboxing se aplica en cualquier lugar en el que se pase como

parmetro un tipo primitivo a un mtodo que espera un tipo envoltorio, y cuando un valor primitivo se almacena en una variable de su correspondiente tipo envoltorio. De manera similar, el proceso de unboxing se aplica cuando un valor de tipo envoltorio se pasa como parmetro a un mtodo que espera un valor de tipo primitivo, y cuando se almacena en una variable de tipo primitivo.

Tipo esttico y tipo dinmico


Volvemos sobre un problema inconcluso: el mtodo imprimir de DoME, no muestra todos los datos de los elementos. El intento de resolver el problema de desarrollar un mtodo imprimir completo y polimrfico nos conduce a la discusin sobre tipos estticos y tipos dinmicos y sobre despacho de mtodos. Comencemos desde el principio. Necesitamos ver ms de cerca los tipos. Consideremos la siguiente sentencia: Elemento e1 = new CD(); Cul es el tipo de e1? Depende de qu queremos decir con tipo de e1. El tipo de la variable e1 es Elemento; (tipo esttico) el tipo del objeto almacenado en e1 es CD. (tipo dinmico) Entonces el tipo esttico de e1 es Elemento y su tipo dinmico es CD. En el momento de la llamada e1.imprimir(); el tipo esttico de la variable elemento es Elemento mientras que su tipo dinmico puede ser tanto CD como DVD. No sabemos cul es su tipo ya que asumimos que hemos ingresado tanto objetos CD como objetos DVD en nuestra base de datos. Y en que clase debe estar codificado el mtodo imprimir()? En tiempo de compilacin necesitamos de la existencia de imprimir() en la clase Elemento, el compilador trabaja con tipo esttico. En tiempo de ejecucin necesitamos de la existencia de un mtodo imprimir() adecuado a los datos del objeto CD o DVD. En definitiva, necesitamos de imprimir() en las tres clases. Aunque no ser lo mismo lo que se imprima en cada uno de ellos. Lo que debemos hacer entonces es

Sobrescribir el mtodo Veamos el mtodo imprimir en cada una de las clases.


public class Elemento{ public void imprimir(){ System.out.print(titulo + " (" + duracion + " minutos) " ); if (loTengo){System.out.println("*"); } else {System.out.println();} System.out.println(" " + comentario); } } public class CD extends Elemento{ public void imprimir(){ System.out.println(" " + interprete); System.out.println(" temas: " + numeroDeTemas); } } public class DVD extends Elemento{ public void imprimir(){ System.out.println(" director: " + director); } } Este diseo funciona mejor: compila y puede ser ejecutado, aunque todava no est perfecto. Proporcionamos una implementacin de este diseo mediante el proyecto

dome-v3. La tcnica que usamos ac se denomina sobrescritura (algunas veces tambin se hace referencia a esta tcnica como redefinicin). La sobrescritura es una situacin en la que un mtodo est definido en una superclase (en este ejemplo, el mtodo imprimir de la clase Elemento) y un mtodo, con exactamente la misma signatura, est definido en la subclase. En esta situacin, los objetos de la subclase tienen dos mtodos con el mismo nombre y la misma signatura: uno heredado de la superclase y el otro propio de la subclase. Cul de estos dos se ejecutar cuando se invoque este mtodo? Bsqueda dinmica del mtodo (Despacho dinmico) Si ejecutamos el mtodo listar de la BaseDeDatos, podremos ver que se ejecutarn los mtodos imprimir de CD y de DVD pero no el de Elemento, y entonces la mayor parte de la informacin, la comn contenida en Elemento, no se imprime. Que est pasando? Vimos que el compilador insisti en que el mtodo imprimir est en la clase Elemento, no le alcanzaba con que los mtodos estuvieran en las subclases. Este experimento ahora nos muestra que el mtodo de la clase Elemento no se ejecuta para nada, pero s se ejecutan los mtodos de las subclases. Ocurre que el control de tipos que realiza el compilador es sobre el tipo esttico, pero en tiempo de ejecucin los mtodos que se ejecutan son los que corresponden al tipo dinmico. Saber esto es muy importante pero todava insuficiente. Para comprenderla mejor, veamos con ms detalle cmo se invocan los mtodos. Este procedimiento se conoce como bsqueda de mtodo, ligadura de mtodo o despacho de mtodo. En este libro, nosotros usamos la terminologa bsqueda de mtodo. Comenzamos con un caso bien sencillo de bsqueda de mtodo. Suponga que tenemos un objeto de clase DVD almacenado en una variable v1 declarada de tipo DVD (Figura 9.5). La clase DVD tiene un mtodo imprimir y no tiene declarada ninguna superclase. Esta es una situacin muy simple que no involucra herencia ni polimorfismo. Ejecutamos v1.imprimir{). Esto requiere de las siguientes acciones: l. Se accede a la variable v1. 2. Se encuentra el objeto almacenado en esa variable (siguiendo la referencia). 3. Se encuentra la clase del objeto (siguiendo la referencia es instancia de). 4. Se encuentra la implementacin del mtodo imprimir en la clase y se ejecuta. Hasta aqu, todo es muy simple. A continuacin, vemos la bsqueda de un mtodo cuando hay herencia. El escenario es similar al anterior, pero esta vez la clase DVD tiene una superclase, Elemento, y el mtodo imprimir est definido slo en la superclase Ejecutamos la misma sentencia. La invocacin al mtodo comienza de manera similar: se ejecutan nuevamente los pasos 1 al 3 del escenario anterior pero luego contina de manera diferente: 4. No se encuentra ningn mtodo imprimir en la clase DVD. 5. Se busca en la superclase un mtodo que coincida. Y esto se hace hasta encontrarlo, subiendo en la jerarqua hasta Object si fuera necesario. Tenga en cuenta que, en

tiempo de ejecucin, debe encontrarse definitivamente un mtodo que coincida, de lo contrario la clase no habra compilado. 6. En nuestro ejemplo, el mtodo imprimir es encontrado en la clase Este ejemplo ilustra la manera en que los objetos heredan los mtodos. Cualquier mtodo que se encuentre en la superclase puede ser invocado sobre un objeto de la subclase y ser correctamente encontrado y ejecutado. Ahora llegamos al escenario ms interesante: la bsqueda de mtodos con una variable polimrfica y un mtodo sobrescrito. Los cambios: . El tipo declarado de la variable v1 ahora es Elemento, no DVD. . El mtodo imprimir est definido en la clase Elemento y redefinido (o sobrescrito) en la clase DVD. Este escenario es el ms importante para comprender el comportamiento de nuestra aplicacin DoME y para encontrar una solucin a nuestro problema con el mtodo imprimir. Los pasos que se siguen para la ejecucin del mtodo son exactamente los mismos pasos 1 al 4, primer caso Observaciones: . No se usa ninguna regla especial para la bsqueda del mtodo en los casos en los que el tipo dinmico no sea igual al tipo esttico. . El mtodo que se encuentra primero y que se ejecuta est determinado por el tipo dinmico, no por el tipo esttico. La instancia con la que estamos trabajando es de la clase DVD, y esto es todo lo que cuenta. Los mtodos sobrescritos en las subclases tienen precedencia sobre los mtodos de las superclases. La bsqueda de mtodo comienza en la clase dinmica de la instancia, esta redefinicin del mtodo es la que se encuentra primero y la que se ejecuta. Esto explica el comportamiento que observamos en nuestro proyecto DoME. Los mtodos imprimir de las subclases (CD y DVD) slo se ejecutan cuando se imprimen los elementos, produciendo listados incompletos. Como podemos solucionarlo?

Llamada a super en mtodos


Ahora que conocemos detalladamente cmo se ejecutan los mtodos sobrescritos podemos comprender la solucin al problema de la impresin. Es fcil ver que lo que queremos lograr es que, para cada llamada al mtodo imprimir de, digamos un objeto CD, se ejecuten para el mismo objeto tanto el mtodo imprimir de la clase Elemento como el de la clase CD. De esta manera se imprimirn todos los detalles. Cuando invoquemos al mtodo imprimir sobre un objeto CD, inicialmente se invocar al mtodo imprimir de la clase CD. En su primera sentencia, este mtodo se convertir en una invocacin al mtodo imprimir de la superclase que imprime la informacin general del elemento. Cuando el control regrese del mtodo de la superclase, las restantes sentencias del mtodo de la subclase imprimirn los campos distintivos de la clase CD. public void imprimir(){ // Mtodo imprimir de la clase CD super.imprimir();

System.out.println(" " + interprete); System.out.println(" temas: ") + numeroDeTemas); } Detalles sobre diferencias del super usado en constructores: el nombre del mtodo de la superclase est explcitamente establecido. Una llamada a super en un mtodo siempre tiene la forma super.nombre-del-mtodo(parmetros); La llamada a super en los mtodos puede ocurrir en cualquier lugar dentro de dicho mtodo. No tiene por qu ser su primer sentencia. La llamada a super no se genera, es completamente opcional.

Mtodo polimrfico
Lo que hemos discutido en las secciones anteriores, desde Tipo esttico y tipo dinmico hasta ahora, es lo que se conoce como despacho de mtodo polimrfico (o mas simplemente, Polimorfismo). Recuerde que una variable polimrfica es aquella que puede almacenar objetos de diversos tipos (cada variable objeto en lava es potencialmente polimrfica). De manera similar, las llamadas a mtodos en lava son polimrficas dado que ellas pueden invocar diferentes mtodos en diferentes momentos. Por ejemplo, la sentencia elemento.imprimir(); puede invocar al mtodo imprimir de CD en un momento dado y al mtodo imprimir de DVD en otro momento, dependiendo del tipo dinmico de la variable elemento. Bueno, no hay mucho ms por ver en herencia y polimorfismo. Claro que para consolidar esto necesitamos verlo funcionando. Para hacer mas completo el demo de polimorfismo, vamos a incorporar un elemento ms: Libro, que extiende directamente Elemento, sin incorporarle ningn atributo adicional. import java.util.ArrayList; public class BaseDeDatos{ private ArrayList<Elemento> elementos; protected String auxStr; public BaseDeDatos(){ // constructor elementos = new ArrayList<Elemento>(); } public void agregarElemento (Elemento elElemento){ elementos.add(elElemento); } public String toString(){ // Cadena con todos los elementos contenidos auxStr = "Contenidos BaseDeDatos\n"; auxStr+=elementos.toString(); return auxStr; } } package dome; public class Elemento{ private String titulo; private int duracion; private boolean loTengo; private String comentario; public Elemento(String elTitulo, int tiempo){ titulo = elTitulo; duracion = tiempo; loTengo = false; comentario = ""; } public String toString(){

String aux = titulo + " (" + duracion + " minutos) "; if (loTengo)aux += "*"; aux += " " + comentario+"\n"; return aux; } } package dome; public class CD extends Elemento{ private String interprete; private int numeroDeTemas; public CD(String elTitulo, String elInterprete, int temas, int tiempo){ super(elTitulo, tiempo); interprete = elInterprete; numeroDeTemas = temas; } public String toString(){ String aux = super.toString(); aux+= " interprete (CD): " + interprete+"\n"; aux+= " temas: " + numeroDeTemas+"\n"; return aux; } } package dome; public class DVD extends Elemento{ private String director; public DVD(String elTitulo, String elDirector, int time){ super(elTitulo, time); director = elDirector; } public String toString(){ String aux = super.toString(); aux+= " director (DVD): " + director+"\n"; return aux; } } package dome; public class Libro extends Elemento{ public Libro(String elTitulo, int time){ super(elTitulo, time); } } package dome; // @author Tymoschuk, Jorge public class Main { private BaseDeDatos db; public void DemoBaseDedatos(){ System.out.println("Demo inicia"); db = new BaseDeDatos(); Elemento elem; // Incluyo 2 CDs elem = new CD("Pajaros en la Cabeza","Amaral",14,35); db.agregarElemento(elem); elem = new CD("One chance","Paul Pots",10,30); db.agregarElemento(elem); // Incluyo 2 DVDs

elem = new DVD("Soy Leyenda","Francis Lawrence",120); db.agregarElemento(elem); elem = new DVD("Nada es Para Siempre","Robert Redford",105); db.agregarElemento(elem); // Incluyo dos libros elem = new Libro("El Seor de los Anillos",5000); db.agregarElemento(elem); elem = new Libro("El Don Apacible",10000); db.agregarElemento(elem); // veamos que hemos hecho System.out.println(db.toString()); System.out.println("Demo terminado"); } public static void main(String[] args) { Main demo = new Main(); demo.DemoBaseDedatos(); } } La sentencia System.out.println(db.toString()), mtodo public void DemoBaseDedatos() es
la que se ejecuta inicialmente. Esta sentencia: Incorpora en la cadena el resultado de elementos.toString. Como elementos es una instancia de ArrayList, usa el toString() de esta clase (De ah los corchetes de cierre y las comas separadoras). elementos contiene 6 instancias de la variable polimrfica Elemento: las dos primeras tienen tipo dinmico CD. Entonces, en la ejecucin del toString() propio invocan super.toString() (el de Elemento) y luego completan con los datos especficos de CD. Las dos siguientes tienen tipo dinmico DVD. Proceden exactamente lo mismo que CD. Las dos ltimas instancias tienen tipo dinmico Libro. Como no tienen toString() propio, el despacho dinmico encuentra el de Elemnto y este es el que se ejecuta. Complicado o facil? En todo caso, la programacin es muy sinttica, nada de sobreescritura, cada parte del armado de la cadena que imprime System.out.println(db.toString()) lo hace el mtodo del objeto responsable de ello, como manda la POO.

4.5 Reutilizacin de cdigo.

Lo primero que se les viene a la cabeza a los estudiantes (y a muchos profesionales) cuando se les menciona la reutilizacin del cdigo es el famoso copiar y pegar al que se han acostumbrado en la programacin estructurada, y de echo muchos lo hacen en poo, lo cual es una de las practicas que ms encarece el desarrollo de software. Como todo en Java, el problema se resuelve con las clases. Para reutilizar el cdigo creamos nuevas clases pero, en lugar de partir de cero, partimos de clases, relacionadas con nuestra clase, que han sido ya creadas y depuradas. El truco est en usar las clases sin ensuciar el cdigo existente. Una forma de hacer esto es crear objetos de nuestras clases existentes dentro de

la nueva clase. Esto se conoce como composicin porque la nueva clase est compuesta de objetos de clases existentes. Estamos reutilizando la funcionalidad del cdigo, y no la forma. Otra forma es crear una nueva clase como un tipo de una clase ya existente. Tomamos la forma de la clase existente y aadimos cdigo a la nueva, sin modificar la clase existente. Esta forma de crear nuevos objetos se llamada herencia, y lo que hacemos es extender la clase en la que nos basamos para crear la nueva.

Composicin:
Hasta ahora hemos usado la composicin de cierta manera, ej. cuando hacemos una interfaz grfica de usuario, nuestra clase de interfaz grfica esta compuesta por un frame, unos panel, botones, etc. todos estos objetos componen el objeto de interfaz grfica. Es decir que la composicin consiste en poner manejadores de objetos dentro de nuestra clase, estos manejadores de objetos no sern otra cosa que instancias de las clases en las que nos estamos basando para crear la nueva clase. Recordemos que la forma para determinar cuando usar composicin es cuando podemos decir que nuestra nueva clase tiene un elemento de otro tipo de objetos, por ejemplo un cronmetro tiene: horas, minutos y segundos, es decir que una clase Cronometro esta compuesta por otras clases llamadas: Horas, Minutos y Segundos. Veamos como seria esta clase:
public class Cronometro { Horas h; Minutos m; Segundos s;

String cadena;

int seg,min,hor;

public Cronometro() { seg=0; min=0; hor=0; h = new Horas(); m = new Minutos(); s = new Segundos(); cadena = new String("0 : 0 : 0"); }

public String avanzar(){ seg = s.forward(); if(seg==0){ min=m.forward(); if(min==0){ hor=h.forward(); } } cadena = hor + " : " + min + " : " + seg; return cadena; }

public String reset(){ seg = s.reset(); min = m.reset(); hor = h.reset(); cadena = hor + " : " + min + " : " + seg; return cadena; } }

Nuestra clase Cronometro est compuesta entre otras cosas por objetos del tipo Horas, Minutos y Segundos y a travs del constructor de nuestra clase creamos las instancias de cada una de ellas.

Herencia:
En java aunque no establezcamos de manera explicita la herencia siempre est presente, ya que todas las clases que creemos heredan de la clase Object, por eso es valido decir que en java todo es un objeto. La sintaxis para la composicin es obvia pero, para realizar la herencia, hay una forma claramente distinta. Cuando heredamos, estamos diciendo "Esta nueva clase es como esa clase antigua", por ejemplo es decir que la clase Horas es una UnidadDeTiempo. Afirmamos esto en el cdigo dando el nombre de la clase como siempre pero, antes de la apertura del lmite cuerpo de clase, pondremos la palabra clave "extends" seguida por el nombre de la clase base. Cuando hagamos esto, obtendremos automticamente todos los datos miembros y mtodos de la clase base. Primero veamos como seria la clase UnidadDeTiempo:

public class UnidadDeTiempo { int valor; int tope;

public int forward(){ if(valor == tope) valor=0; else valor++; return valor; }

public int reset(){ valor=0; return valor; } }

Y nuestra clase Horas:

public class Horas extends UnidadDeTiempo{ public Horas() { this.valor=0; this.tope=23; } }

De esta manera sin necesidad de tener que escribir nuevamente todos el cdigo de UnidadDeTiempo lo tememos disponible en la clase Horas, pero que partes tenemos disponibles?, todos los atributos y los mtodos de la clase padre estn disponibles en la clase hija pero dependiendo de los modificadores de acceso o visibilidad de estos, por ejemplo los atributos y mtodos de tipo friendly solo estarn disponibles para las clases hijas que heredan de una clase padre en el mismo paquete, los atributos y mtodos de tipo public estarn disponibles para todas las clases que hereden de la clase padre sin importar que se halle o no en el mismo paquete; los miembros protected tambin son accesibles desde las clases hijas. El cdigo de nuestra clases hijas no tienen porque limitarse solo al cdigo heredado, de hecho casi siempre la herencia se hace para extender la funcionalidad de las clases heredadas aadiendo nuevos mtodos y atributos.

La composicin y la herencia:
Tanto la composicin como la herencia permiten poner sub-objetos dentro de tu nueva clase. Podramos preguntarnos cul es la diferencia entre los dos, y cundo elegir uno en lugar del otro. La composicin es generalmente usada cuando

deseamos las caractersticas de una clase existente dentro de una nueva clase, pero no su interfaz. Es decir, ponemos un para poder usarlo para implementar caractersticas de nuestra nueva clase, pero el usuario de esa nueva clase ver el interfaz que hemos definido en lugar del interfaz del objeto insertado. Los objetos miembros usan la implementacin ocultndose a s mismos, por lo que esto es una cosa segura a hacer y, cuando el usuario sabe que estamos uniendo un conjunto de partes, hace que el interfaz sea ms fcil de entender. Cuando heredamos, estamos cogiendo una clase existente y creando una versin especial de esa clase. En general, esto significa que estamos tomando una clase de propsito general, especializndola para un caso o necesidad particular. Pensando un poco, podr entender que no tendra sentido construir un coche usando un objeto vehculo (un coche no contiene un vehculo, es un vehculo!). La relacin es- un viene expresada por la herencia, y la relacin tiene un viene expresada por la composicin.

Potrebbero piacerti anche