Está en la página 1de 14

Unidad 10.

Polimorfismo
10.1 Introduccin
El polimorfismo nos permite escribir programas para procesar objetos que compartan la misma superclase en una jerarqua de clases, como si todos fueran objetos de la superclase; esto puede simplificar la programacin. Con el polimorfismo, podemos disear e implementar sistemas que puedan extenderse con facilidad; pueden agregarse nuevas clases con slo modificar un poco (o nada) las porciones generales del programa, siempre y cuando las nuevas clases sean parte de la jerarqua de herencia que el programa procesa en forma genrica. Las nicas partes de un programa que deben alterarse para dar cabida a las nuevas clases son las que requieren un conocimiento directo de las nuevas clases que el programador agregar a la jerarqua.

10.3 Demostracin del comportamiento polimrfico


Cuando el compilador encuentra una llamada a un mtodo que se realiza a travs de una variable, determina si el mtodo puede llamarse verificando el tipo de clase de la variable. Si esa clase contiene la declaracin del mtodo apropiada (o hereda una), se compila la llamada. En tiempo de ejecucin, el tipo del objeto al cual se refiere la variable es el que determina el mtodo que se utilizar.

// Fig. 10.1: PruebaPolimorfismo.java // Asignacin de referencias a la superclase y la subclase, a variables de la superclase y la subclase. public class PruebaPolimorfismo { public static void main( String args[] ) { // asigna la referencia a la superclase a una variable de la superclase EmpleadoPorComision3 empleadoPorComision = new EmpleadoPorComision3( "Sue", "Jones", "222-22-2222", 10000, .06 ); // asigna la referncia a la subclase a una variable de la subclase EmpleadoBaseMasComision4 empleadoBaseMasComision = new EmpleadoBaseMasComision4( "Bob", "Lewis", "333-33-3333", 5000, .04, 300 ); // invoca a toString en un objeto de la superclase, usando una variable de la superclase System.out.printf( "%s %s:\n\n%s\n\n", "Llamada a toString de EmpleadoPorComision3 con referencia de superclase ", "a un objeto de la superclase", empleadoPorComision.toString() ); // invoca a toString en un objeto de la subclase, usando una variable de la subclase System.out.printf( "%s %s:\n\n%s\n\n", "Llamada a toString de EmpleadoBaseMasComision4 con referencia", "de subclase a un objeto de la subclase", empleadoBaseMasComision.toString() ); // invoca a toString en un objeto de la subclase, usando una variable de la superclase EmpleadoPorComision3 empleadoPorComision2 = empleadoBaseMasComision; System.out.printf( "%s %s:\n\n%s\n", "Llamada a toString de EmpleadoBaseMasComision4 con referencia de superclase", "a un objeto de la subclase", empleadoPorComision2.toString() ); } // fin de main } // fin de la clase PruebaPolimorfismo
Llamada a toString de EmpleadoPorComision3 con referencia de superclase a un objeto de la superclase: empleado por comision: Sue Jones numero de seguro social: 222-22-2222 ventas brutas: 10000.00 tarifa de comision: 0.06

10.4 Clases y mtodos abstractos


En algunos casos es conveniente declarar clases para las cuales no tenemos la intencin de crear instancias de objetos. A dichas clases se les conoce como clases abstractas. Como se utilizan slo como superclases en jerarquas de herencia, nos referimos a ellas como superclases abstractas. Estas clases no pueden utilizarse para instanciar objetos, ya que estn incompletas. El propsito principal de una clase abstracta es proporcionar una superclase apropiada, a partir de la cual puedan heredar otras clases y, por ende, compartir un diseo comn. Las clases que pueden utilizarse para instanciar objetos se llaman clases concretas. Dichas clases proporcionan implementaciones de cada mtodo que declaran (algunas de las implementaciones pueden heredarse). No todas las jerarquas de herencia contienen clases abstractas. Sin embargo, a menudo los programadores escriben cdigo cliente que utiliza slo tipos de superclases abstractas para reducir las dependencias del cdigo cliente en un rango de tipos de subclases especficas. Algunas veces las clases abstractas constituyen varios niveles de la jerarqua. Para hacer una clase abstracta, sta se declara con la palabra clave abstract. Por lo general, una clase abstracta contiene uno o ms mtodos abstractos. Los mtodos abstractos no proporcionan implementaciones. Una clase que contiene mtodos abstractos debe declararse como clase abstracta, aun si esa clase contiene mtodos concretos (no abstractos). Cada subclase concreta de una superclase abstracta tambin debe proporcionar implementaciones concretas de los mtodos abstractos de la superclase. Los constructores y los mtodos static no pueden declararse como abstract. Aunque no podemos instanciar objetos de superclases abstractas, s podemos usar superclases abstractas para declarar variables que puedan guardar referencias a objetos de cualquier clase concreta que se derive de esas superclases abstractas. Por lo general, los programas utilizan dichas variables para manipular los objetos de las subclases mediante el polimorfismo. En especial, el polimorfismo es efectivo para implementar los sistemas de software en capas.

10.5 Ejemplo prctico: sistema de nmina utilizando polimorfismo


Al incluir un mtodo abstracto en una superclase, obligamos a cada subclase directa de la superclase a sobrescribir ese mtodo abstracto para que pueda convertirse en una clase concreta. Esto permite al diseador de la jerarqua de clases demandar que cada subclase concreta proporcione una implementacin apropiada del mtodo. La mayora de las llamadas a los mtodos se resuelven en tiempo de ejecucin, con base en el tipo del objeto que se est manipulando. Este proceso se conoce como vinculacin dinmica o vinculacin postergada. Una referencia a la superclase puede utilizarse para invocar slo a mtodos de la superclase (y la superclase puede invocar versiones sobrescritas de stos en la subclase).

El operador instanceof se puede utilizar para determinar si el tipo de un objeto especfico tiene la relacin es un con un tipo especfico. Todos los objetos en Java conocen su propia clase y pueden acceder a esta informacin a travs del mtodo getClass, que todas las clases heredan de la clase Object. El mtodo getClass devuelve un objeto de tipo Class (del paquete java.lang), el cual contiene informacin acerca del tipo del objeto, incluyendo el nombre de su clase.

La relacin es un se aplica slo entre la subclase y sus superclases, no viceversa. No est permitido tratar de invocar a los mtodos que slo pertenecen a la subclase, en una referencia a la superclase. Aunque el mtodo que se llame en realidad depende del tipo del objeto en tiempo de ejecucin, podemos usar una variable para invocar slo a los mtodos que sean miembros del tipo de esa variable, que el compilador verifica.

// Fig. 10.4: Empleado.java La superclase abstracta Empleado. public abstract class Empleado { private String primerNombre; private String apellidoPaterno; private String numeroSeguroSocial; // constructor con tres argumentos public Empleado( String nombre, String apellido, String nss ) { primerNombre = nombre; apellidoPaterno = apellido; numeroSeguroSocial = nss; } // fin del constructor de Empleado con tres argumentos // establece el primer nombre public void establecerPrimerNombre( String nombre ) { primerNombre = nombre; } // fin del mtodo establecerPrimerNombre // devuelve el primer nombre public String obtenerPrimerNombre() { return primerNombre; } // fin del mtodo obtenerPrimerNombre // establece el apellido paterno public void establecerApellidoPaterno( String apellido ) { apellidoPaterno = apellido; } // fin del mtodo establecerApellidoPaterno // devuelve el apellido paterno public String obtenerApellidoPaterno() { return apellidoPaterno; } // fin del mtodo obtenerApellidoPaterno // establece el nmero de seguro social public void establecerNumeroSeguroSocial( String nss ) { numeroSeguroSocial = nss; // debe validar } // fin del mtodo establecerNumeroSeguroSocial // devuelve el nmero de seguro social public String obtenerNumeroSeguroSocial() { return numeroSeguroSocial; } // fin del mtodo obtenerNumeroSeguroSocial // devuelve representacin String de un objeto Empleado public String toString() { return String.format( "%s %s\nnumero de seguro social: %s", obtenerPrimerNombre(), obtenerApellidoPaterno(), obtenerNumeroSeguroSocial() ); } // fin del mtodo toString // mtodo abstracto sobrescrito por las subclases public double ingresos(); // extends aqu no hay implementacin publicabstract class EmpleadoAsalariado Empleado {

// Fig. 10.5: EmpleadoAsalariado.java La clase EmpleadoAsalariado extiende a Empleado.

private salarioSemanal; } // fin de la double clase abstracta Empleado // constructor de cuatro argumentos public EmpleadoAsalariado( String nombre, String apellido, String nss, double salario ) { super( nombre, apellido, nss ); // los pasa al constructor de Empleado establecerSalarioSemanal( salario ); // valida y almacena el salario } // fin del constructor de EmpleadoAsalariado con cuatro argumentos // establece el salario

// Fig. 10.6: EmpleadoPorHoras.java La clase EmpleadoPorHoras extiende a Empleado. public class EmpleadoPorHoras extends Empleado { private double sueldo; // sueldo por hora private double horas; // horas trabajadas por semana // constructor con cinco argumentos public EmpleadoPorHoras( String nombre, String apellido, String nss, double sueldoPorHoras, double horasTrabajadas ) { super( nombre, apellido, nss ); establecerSueldo( sueldoPorHoras ); // valida y almacena el sueldo por horas establecerHoras( horasTrabajadas ); // valida y almacena las horas trabajadas } // fin del constructor de EmpleadoPorHoras con cinco argumentos // establece el sueldo public void establecerSueldo( double sueldoPorHoras ) { sueldo = ( sueldoPorHoras < 0.0 ) ? 0.0 : sueldoPorHoras; } // fin del mtodo establecerSueldo // devuelve el sueldo public double obtenerSueldo() { return sueldo; } // fin del mtodo obtenerSueldo // establece las horas trabajadas public void establecerHoras( double horasTrabajadas ) { horas = ( ( horasTrabajadas >= 0.0 ) && ( horasTrabajadas <= 168.0 ) ) ? horasTrabajadas : 0.0; } // fin del mtodo establecerHoras

Figura 10.6 | La clase EmpleadoPorHoras derivada de Empleado (Parte 1 de 2).

// devuelve las horas trabajadas public double obtenerHoras() { return horas; } // fin del mtodo obtenerHoras // calcula los ingresos; sobrescribe el mtodo abstracto ingresos en Empleado public double ingresos() { if ( obtenerHoras() <= 40 ) // no hay tiempo extra return obtenerSueldo() * obtenerHoras(); else return 40 * obtenerSueldo() + ( obtenerHoras() - 40 ) * obtenerSueldo() * 1.5; } // fin del mtodo ingresos // devuelve representacin String de un objeto EmpleadoPorHoras public String toString() { return String.format( "empleado por horas: %s\n%s: $%,.2f; %s: %,.2f", super.toString(), "sueldo por hora", obtenerSueldo(), "horas trabajadas", obtenerHoras() ); } // fin del mtodo toString } // fin de la clase EmpleadoPorHoras

Figura 10.6 | La clase EmpleadoPorHoras derivada de Empleado (Parte 2 de 2).

// Fig. 10.7: EmpleadoPorComision.java La clase EmpleadoPorComision extiende a Empleado. public class EmpleadoPorComision extends Empleado { private double ventasBrutas; // ventas totales por semana private double tarifaComision; // porcentaje de comisin // constructor con cinco argumentos public EmpleadoPorComision( String nombre, String apellido, String nss, double ventas, double tarifa ) { super( nombre, apellido, nss ); establecerVentasBrutas( ventas ); establecerTarifaComision( tarifa ); } // fin del constructor de EmpleadoPorComision con cinco argumentos // establece la tarifa de comisin public void establecerTarifaComision( double tarifa ) { tarifaComision = ( tarifa > 0.0 && tarifa < 1.0 ) ? tarifa : 0.0; } // fin del mtodo establecerTarifaComision // devuelve la tarifa de comisin public double obtenerTarifaComision() { return tarifaComision; } // fin del mtodo obtenerTarifaComision // establece el monto de ventas brutas public void establecerVentasBrutas( double ventas ) { ventasBrutas = ( ventas < 0.0 ) ? 0.0 : ventas; } // fin del mtodo establecerVentasBrutas // devuelve el monto de ventas brutas public double obtenerVentasBrutas() { return ventasBrutas; } // fin del mtodo obtenerVentasBrutas

Figura 10.7 | La clase EmpleadoPorComision derivada de Empleado. (Parte 1 de 2).

// calcula los ingresos; sobrescribe el mtodo abstracto ingresos en Empleado public double ingresos() { return obtenerTarifaComision() * obtenerVentasBrutas(); } // fin del mtodo ingresos // devuelve representacin String de un objeto EmpleadoPorComision public String toString() { return String.format( "%s: %s\n%s: $%,.2f; %s: %.2f", "empleado por comision", super.toString(), "ventas brutas", obtenerVentasBrutas(), "tarifa de comision", obtenerTarifaComision() ); } // fin del mtodo toString } // fin de la clase EmpleadoPorComision

Figura 10.7 | La clase EmpleadoPorComision derivada de Empleado. (Parte 2 de 2).

// Fig. 10.8: EmpleadoBaseMasComision.java // La clase EmpleadoBaseMasComision extiende a EmpleadoPorComision. public class EmpleadoBaseMasComision extends EmpleadoPorComision { private double salarioBase; // salario base por semana // constructor con seis argumentos public EmpleadoBaseMasComision( String nombre, String apellido, String nss, double ventas, double tarifa, double salario ) { super( nombre, apellido, nss, ventas, tarifa ); establecerSalarioBase( salario ); // valida y almacena el salario base } // fin del constructor de EmpleadoBaseMasComision con seis argumentos // establece el salario base public void establecerSalarioBase( double salario ) { salarioBase = ( salario < 0.0 ) ? 0.0 : salario; // positivo } // fin del mtodo establecerSalarioBase // devuelve el salario base public double obtenerSalarioBase() { return salarioBase; } // fin del mtodo obtenerSalarioBase // calcula los ingresos; sobrescribe el mtodo ingresos en EmpleadoPorComision public double ingresos() { return obtenerSalarioBase() + super.ingresos(); } // fin del mtodo ingresos // devuelve representacin String de un objeto EmpleadoBaseMasComision public String toString() { return String.format( "%s %s; %s: $%,.2f", "con salario base", super.toString(), "salario base", obtenerSalarioBase() ); } // fin del mtodo toString } // fin de la clase EmpleadoBaseMasComision

// Fig. 10.9: PruebaSistemaNomina.java // Programa de prueba para la jerarqua de Empleado. public class PruebaSistemaNomina { public static void main( String args[] ) { // crea objetos de las subclases EmpleadoAsalariado empleadoAsalariado = new EmpleadoAsalariado( "John", "Smith", "111-11-1111", 800.00 ); EmpleadoPorHoras empleadoPorHoras = new EmpleadoPorHoras( "Karen", "Price", "222-22-2222", 16.75, 40 ); EmpleadoPorComision empleadoPorComision = new EmpleadoPorComision( "Sue", "Jones", "333-33-3333", 10000, .06 ); EmpleadoBaseMasComision empleadoBaseMasComision = new EmpleadoBaseMasComision( "Bob", "Lewis", "444-44-4444", 5000, .04, 300 ); System.out.println( "Empleados procesados por separado:\n" ); System.out.printf( "%s\n%s: $%,.2f\n\n", empleadoAsalariado, "ingresos", empleadoAsalariado.ingresos() ); System.out.printf( "%s\n%s: $%,.2f\n\n", empleadoPorHoras, "ingresos", empleadoPorHoras.ingresos() ); System.out.printf( "%s\n%s: $%,.2f\n\n", empleadoPorComision, "ingresos", empleadoPorComision.ingresos() ); System.out.printf( "%s\n%s: $%,.2f\n\n", empleadoBaseMasComision, "ingresos", empleadoBaseMasComision.ingresos() ); // crea un arreglo Empleado de cuatro elementos Empleado empleados[] = new Empleado[ 4 ]; // inicializa el arreglo con objetos Empleado empleados[ 0 ] = empleadoAsalariado; empleados[ 1 ] = empleadoPorHoras; empleados[ 2 ] = empleadoPorComision; empleados[ 3 ] = empleadoBaseMasComision; System.out.println( "Empleados procesados en forma polimorfica:\n" ); // procesa en forma genrica a cada elemento en el arreglo de empleados for ( Empleado empleadoActual : empleados ) { System.out.println( empleadoActual ); // invoca a toString // determina si el elemento es un EmpleadoBaseMasComision if ( empleadoActual instanceof EmpleadoBaseMasComision ) { // conversin descendente de la referencia de Empleado a una referencia de EmpleadoBaseMasComision EmpleadoBaseMasComision empleado = ( EmpleadoBaseMasComision ) empleadoActual; double salarioBaseAnterior = empleado.obtenerSalarioBase(); empleado.establecerSalarioBase( 1.10 * salarioBaseAnterior ); System.out.printf( "el nuevo salario base con 10%% de aumento es : $%,.2f\n", empleado.obtenerSalarioBase() ); } // fin de if System.out.printf( "ingresos $%,.2f\n\n", empleadoActual.ingresos() ); } // fin de for // obtiene el nombre del tipo de cada objeto en el arreglo de empleados for ( int j = 0; j < empleados.length; j++ ) System.out.printf( "El empleado %d es un %s\n", j, empleados[ j ].getClass().getName() ); } // fin de main } // fin de la clase PruebaSistemaNomina

Empleados procesados por separado: empleado asalariado: John Smith numero de seguro social: 111-11-1111 salario semanal: $800.00 ingresos: $800.00 empleado por horas: Karen Price numero de seguro social: 222-22-2222 sueldo por hora: $16.75; horas trabajadas: 40.00 ingresos: $670.00 empleado por comision: Sue Jones numero de seguro social: 333-33-3333 ventas brutas: $10,000.00; tarifa de comision: 0.06 ingresos: $600.00 con salario base empleado por comision: Bob Lewis numero de seguro social: 444-44-4444 ventas brutas: $5,000.00; tarifa de comision: 0.04; salario base: $300.00 ingresos: $500.00 Empleados procesados en forma polimorfica: empleado asalariado: John Smith numero de seguro social: 111-11-1111 salario semanal: $800.00 ingresos $800.00 empleado por horas: Karen Price numero de seguro social: 222-22-2222 sueldo por hora: $16.75; horas trabajadas: 40.00 ingresos $670.00 empleado por comision: Sue Jones numero de seguro social: 333-33-3333 ventas brutas: $10,000.00; tarifa de comision: 0.06 ingresos $600.00 con salario base empleado por comision: Bob Lewis numero de seguro social: 444-44-4444 ventas brutas: $5,000.00; tarifa de comision: 0.04; salario base: $300.00 el nuevo salario base con 10% de aumento es : $330.00 ingresos $530.00 El empleado 0 es un EmpleadoAsalariado El empleado 1 es un EmpleadoPorHoras El empleado 2 es un EmpleadoPorComision El empleado 3 es un EmpleadoBaseMasComision

10.6 Mtodos y clases final


Un mtodo que se declara como final en una superclase no se puede redefinir en una subclase. Los mtodos que se declaran como private son final de manera implcita, ya que es imposible sobrescribirlos en una subclase. Los mtodos que se declaran como static son final de manera implcita. La declaracin de un mtodo final no puede cambiar, por lo que todas las subclases utilizan la misma implementacin del mtodo, y las llamadas a los mtodos final se resuelven en tiempo de compilacin; a esto se le conoce como vinculacin esttica. Como el compilador sabe que los mtodos final no se pueden sobrescribir, puede optimizar los programas al eliminar las llamadas a los mtodos final y sustituirlas con el cdigo expandido de sus declaraciones en cada una de las ubicaciones de las llamadas al mtodo; a esta tcnica se le conoce como poner el cdigo en lnea. Una clase que se declara como final no puede ser una superclase (es decir, una clase no puede extender a una clase final). Todos los mtodos en una clase final son implcitamente final.

10.7 Ejemplo prctico: creacin y uso de interfaces


Las interfaces definen y estandarizan las formas en que las cosas como las personas y los sistemas pueden interactuar entre s. Una interfaz especifica qu operaciones estn permitidas, pero no especifica cmo se realizan estas operaciones. Una interfaz de Java describe a un conjunto de mtodos que pueden llamarse en un objeto. La declaracin de una interfaz empieza con la palabra clave interface y slo contiene constantes y mtodos abstract. Todos los miembros de una interfaz deben ser public, y las interfaces no pueden especificar ningn detalle de implementacin, como las declaraciones de mtodos concretos y las variables de instancia. Todos los mtodos que se declaran en una interfaz son public abstract de manera implcita, y todos los campos son public, static y final de manera implcita. Para utilizar una interfaz, una clase concreta debe especificar que implementa (implements) a esa interfaz, y debe declarar cada uno de los mtodos de la interfaz con la firma especificada en su declaracin. Una clase que no implementa a todos los mtodos de una interfaz es una clase abstracta, por lo cual debe declararse como abstract. Implementar una interfaz es como firmar un contrato con el compilador que diga, Declarar todos los mtodos especificados por la interfaz, o declarar mi clase como abstract. Por lo general, una interfaz se utiliza cuando clases dispares (es decir, no relacionadas) necesitan compartir mtodos y constantes comunes. Esto permite que los objetos de clases no relacionadas se procesen en forma polimrfica; los objetos de clases que implementan la misma interfaz pueden responder a las mismas llamadas a mtodos. Usted puede crear una interfaz que describa la funcionalidad deseada, y despus implementar esa interfaz en cualquier clase que requiera esa funcionalidad. A menudo, una interfaz se utiliza en vez de una clase abstract cuando no hay una implementacin predeterminada que heredar; esto es, no hay campos ni implementaciones de mtodos predeterminadas. Al igual que las clases public abstract, las interfaces son comnmente de tipo public, por lo que se declaran en archivos por s solas con el mismo nombre que la interfaz, y la extensin de archivo .java. Java no permite que las subclases hereden de ms de una superclase, pero s permite que una clase herede de una superclase e implemente ms de una interfaz. Para implementar ms de una interfaz, utilice una lista separada por comas de nombres de interfaz despus de la palabra clave implements en la declaracin de la clase. Todos los objetos de una clase que implementan varias interfaces tienen la relacin es un con cada tipo de interfaz implementada. Una interfaz puede declarar constantes. Las constantes son implcitamente public, static y final.

// Fig. 10.11: PorPagar.java Declaracin de la interfaz PorPagar. public interface PorPagar { double obtenerMontoPago(); // calcula el pago; no hay implementacin } // fin de la interfaz PorPagar

// Fig. 10.12: Factura.java La clase Factura implementa a PorPagar. public class Factura implements PorPagar { private String numeroPieza; private String descripcionPieza; private int cantidad; private double precioPorArticulo; // constructor con cuatro argumentos public Factura( String pieza, String descripcion, int cuenta, double precio ) { numeroPieza = pieza; descripcionPieza = descripcion; establecerCantidad( cuenta ); // valida y almacena la cantidad establecerPrecioPorArticulo( precio ); // valida y almacena el precio por artculo } // find el constructor de Factura con cuatro argumentos public void establecerNumeroPieza( String pieza ) { // establece el nmero de pieza numeroPieza = pieza; } // fin del mtodo establecerNumeroPieza public String obtenerNumeroPieza() { // obtener nmero de pieza return numeroPieza; } // fin del mtodo obtenerNumeroPieza public void establecerDescripcionPieza( String descripcion ) { // establece la descripcin descripcionPieza = descripcion; } // fin del mtodo establecerDescripcionPieza public String obtenerDescripcionPieza() { // obtiene la descripcin return descripcionPieza; } // fin del mtodo obtenerDescripcionPieza public void establecerCantidad( int cuenta ) { // establece la cantidad cantidad = ( cuenta < 0 ) ? 0 : cuenta; // cantidad no puede ser negativa } // fin del mtodo establecerCantidad public int obtenerCantidad() { // obtener cantidad return cantidad; } // fin del mtodo obtenerCantidad // establece el precio por artculo public void establecerPrecioPorArticulo( double precio ) { precioPorArticulo = ( precio < 0.0 ) ? 0.0 : precio; // valida el precio } // fin del mtodo establecerPrecioPorArticulo public double obtenerPrecioPorArticulo() { // obtiene el precio por artculo return precioPorArticulo; } // fin del mtodo obtenerPrecioPorArticulo public String toString() { // devuelve representacin String de un objeto Factura return String.format( "%s: \n%s: %s (%s) \n%s: %d \n%s: $%,.2f", "factura", "numero de pieza", obtenerNumeroPieza(), obtenerDescripcionPieza(), "cantidad", obtenerCantidad(), "precio por articulo", obtenerPrecioPorArticulo() ); } // fin del mtodo toString // mtodo requerido para realizar el contrato con la interfaz PorPagar public double obtenerMontoPago() { return obtenerCantidad() * obtenerPrecioPorArticulo(); // calcula el costo total } // fin del mtodo obtenerMontoPago } // fin de la clase Factura

// Fig. 10.13: Empleado.java // La superclases abstracta Empleado implementa a PorPagar. public abstract class Empleado implements PorPagar { private String primerNombre; private String apellidoPaterno; private String numeroSeguroSocial; // constructor con tres argumentos public Empleado( String nombre, String apellido, String nss ) { primerNombre = nombre; apellidoPaterno = apellido; numeroSeguroSocial = nss; } // fin del constructor de Empleado con tres argumentos // establece el primer nombre public void establecerPrimerNombre( String nombre ) { primerNombre = nombre; } // fin del mtodo establecerPrimerNombre // devuelve el primer nombre public String obtenerPrimerNombre() { return primerNombre; } // fin del mtodo obtenerPrimerNombre // establece el apellido paterno public void establecerApellidoPaterno( String apellido ) { apellidoPaterno = apellido; } // fin del mtodo establecerApellidoPaterno // devuelve el apellido paterno public String obtenerApellidoPaterno() { return apellidoPaterno; } // fin del mtodo obtenerApellidoPaterno // establece el nmero de seguro social public void establecerNumeroSeguroSocial( String nss ) { numeroSeguroSocial = nss; // debe validar } // fin del mtodo establecerNumeroSeguroSocial // devuelve el nmero de seguro social public String obtenerNumeroSeguroSocial() { return numeroSeguroSocial; } // fin del mtodo obtenerNumeroSeguroSocial // devuelve representacin String de un objeto Empleado public String toString() { return String.format( "%s %s\nnumero de seguro social: %s", obtenerPrimerNombre(), obtenerApellidoPaterno(), obtenerNumeroSeguroSocial() ); } // fin del mtodo toString // Nota: Aqu no implementamos el mtodo obtenerMontoPago de PorPagar, as que // esta clase debe declararse como abstract para evitar un error de compilacin. } // fin de la clase abstracta Empleado

// Fig. 10.14: EmpleadoAsalariado.java // La clase EmpleadoAsalariado extiende a Empleado, que implementa a PorPagar. public class EmpleadoAsalariado extends Empleado { private double salarioSemanal; // constructor con cuatro argumentos public EmpleadoAsalariado( String nombre, String apellido, String nss, double salario ) { super( nombre, apellido, nss ); // pasa argumentos al constructor de Empleado establecerSalarioSemanal( salario ); // valida y almacena el salario } // fin del constructor de EmpleadoAsalariado con cuatro argumentos // establece el salario public void establecerSalarioSemanal( double salario ) { salarioSemanal = salario < 0.0 ? 0.0 : salario; } // fin del mtodo establecerSalarioSemanal // devuelve el salario public double obtenerSalarioSemanal() { return salarioSemanal; } // fin del mtodo obtenerSalarioSemanal // calcula los ingresos; implementa el mtodo de la interfaz PorPagar // que era abstracto en la superclase Empleado public double obtenerMontoPago() { return obtenerSalarioSemanal(); } // fin del mtodo obtenerMontoPago // devuelve representacin String de un objeto EmpleadoAsalariado public String toString() { return String.format( "empleado asalariado: %s\n%s: $%,.2f", super.toString(), "salario semanal", obtenerSalarioSemanal() ); } // fin del mtodo toString } // fin de la clase EmpleadoAsalariado

// Fig. 10.15: PruebaInterfazPorPagar.java Prueba la interfaz PorPagar. public class PruebaInterfazPorPagar { public static void main( String args[] ) { // crea arreglo PorPagar con cuatro elementos PorPagar objetosPorPagar[] = new PorPagar[ 4 ]; // llena el arreglo con objetos que implementan la interfaz PorPagar objetosPorPagar[ 0 ] = new Factura( "01234", "asiento", 2, 375.00 ); objetosPorPagar[ 1 ] = new Factura( "56789", "llanta", 4, 79.95 ); objetosPorPagar[ 2 ] = new EmpleadoAsalariado( "John", "Smith", "111-11-1111", 800.00 ); objetosPorPagar[ 3 ] = new EmpleadoAsalariado( "Lisa", "Barnes", "888-88-8888", 1200.00 ); System.out.println( "Facturas y Empleados procesados en forma polimorfica:\n" ); // procesa en forma genrica cada elemento en el arreglo objetosPorPagar for ( PorPagar porPagarActual : objetosPorPagar ) { // imprime porPagarActual y su monto de pago apropiado System.out.printf( "%s \n%s: $%,.2f\n\n", porPagarActual.toString(), "pago vencido", porPagarActual.obtenerMontoPago() ); } // fin de for } // fin de main } // fin de la clase PruebaInterfazPorPagar

10.7.8 Interfaces comunes de la API de Java