miércoles, 20 de octubre de 2010

Herencia (RELATORIA)

RELATORIA

Herencia en java

Java permite el empleo de la herencia , característica muy potente que permite definir una clase tomando como base a otra clase ya existente. Esto es una de las bases de la reutilización de código, en lugar de copiar y pegar.
En java, como ya vimos la herencia se especifica agregando la claúsula extends después del nombre de la clase. En la claúsula extends indicaremos el nombre de la clase base de la cuál queremos heredar.
Al heredar de una clase base, heredaremos tanto los atributos como los métodos, mientras que los constructores son utilizados, pero no heredados.

Herencia Simple: Indica que se pueden definir nuevas clases solamente a partir de una clase inicial. Ejemplo:


Herencia múltiple: Indica que se pueden definir nuevas clases a partir de dos o más clases iniciales. Ejemplo:



Clase Abstracta:

Características: 
1.   No se instancia.
2.   Se usa únicamente para definir subclases.

¿Cuando es una clase abstracta?
En cuanto a uno de sus métodos no tiene implementación (En java, el método abstracto se etiqueta con la palabra reservada abstract) .

¿Cuando se utilizan clases abstractas?
Cuando deseamos definir una abstracción que englobe objetos de distintos tipos y queremos hacer uso del polimorfismo.

Ejemplo:
 

Interface en java


Una interface es un conjunto de declaraciones de funciones.Si una clase implementa (implements)
una interface, debe definir todas las funciones especificadas por la interface. Una clase puede implementar mas de una interface, representando una forma alternativa de la herencia múltiple.
A su vez, una  interface puede derivar de otra o incluso de varias interfaces, en cuyo caso incorpora todos
los métodos de las interfaces de las que deriva.



Una interface se declara:
interface nombre_interface {
    tipo_retorno nombre_metodo lista_argumentos ) ;
    . . .
}
Por ejemplo:
interface InstrumentoMusical {
    void tocar();
    void afinar();
    String tipoInstrumento();
}
Y una clase que implementa la interface:
class InstrumentoViento extends Object implements InstrumentoMusical {
    void tocar() { . . . };
    void afinar() { . . .};
    String tipoInstrumento() {}
}

class Guitarra extends InstrumentoViento {
    String tipoInstrumento() {
        return "Guitarra";
    }
}   
La clase InstrumentoViento implementa la interface, declarando los métodos y escribiendo el código correspondiente. Una clase derivada puede también redefinir si es necesario alguno de los métodos de la interface. 

Referencias a Interfaces

Es posible crear referencias a interfaces, pero las interfaces no pueden ser instanciadas. Una referencia a una interface puede ser asignada a cualquier objeto que implemente la interface. Por ejemplo:
InstrumentoMusical instrumento = new Guitarra();
instrumento.play();
System.out.prinln(instrumento.tipoInstrumento());

InstrumentoMusical i2 = new InstrumentoMusical(); //error.No se puede instanciar

Extensión de interfaces

Las interfaces pueden extender otras interfaces y, a diferencia de las clases, una interface puede extender más de una interface. La sintaxis es:
interface nombre_interface  extends nombre_interface  , . . . {
    tipo_retorno nombre_metodo lista_argumentos ) ;
    . . .
}

Agrupaciones de constantes

Dado que, por definición, todos los datos miembros que se definen en una interface son static y final, y dado que las interfaces no pueden instanciarse resultan una buena herramienta para implantar grupos de constantes. Por ejemplo:
public interface Meses {
    int ENERO = 1 , FEBRERO = 2 . . . ;
    String [] NOMBRES_MESES = { " " , "Enero" , "Febrero" , . . . };
}
Esto puede usarse simplemente:
System.out.println(Meses.NOMBRES_MESES[ENERO]);

Un ejemplo casi real

El ejemplo mostrado a continuación es una simplificación de como funciona realmente la gestión de eventos en el sistema gráfico de usuario soportado por el API de Java (AWT o swing). Se han cambiado los nombres y se ha simplificado para mostrar un caso real en que el uso de interfaces resuelve un problema concreto.
Supongamos que tenemos una clase que representa un botón de acción en un entorno gráfico de usuario (el típico botón de confirmación de una acción o de cancelación). Esta clase pertenecerá a una amplia jerarquía de clases y tendrá mecanismos complejos de definición y uso que no son objeto del ejemplo. Sin embargo podríamos pensar que  la clase Boton tiene miembros como los siguientes.
class Boton extends . . . {
    protected int x , y, ancho, alto; // posicion del boton
    protected String texto;  // texto del boton
    Boton(. . .) {
        . . .
    }
    void dibujar() { . . .}
    public void asignarTexto(String t) { . . .}
    public String obtenerTexto() { . . .)
    . . .
}   
Lo que aquí nos interesa es ver lo que sucede cuando el usuario, utilizando el ratón pulsa sobre el botón. Supongamos que la clase Boton tiene un método, de nombre por ejemplo click(), que es invocado por el gestor de ventanas cuando ha detectado que el usuario ha pulsado el botón del ratón sobre él. El botón deberá realizar alguna acción como dibujarse en posición 'pulsado' (si tiene efectos de tres dimensiones) y además, probablemente, querrá informar a alguien de que se ha producido la acción del usuario. Es en este mecanismo de 'notificación' donde entra el concepto de interface. Para ello definimos una interface Oyente de la siguiente forma:
interface Oyente {
    void botonPulsado(Boton b);
}
La interface define un único método botonPulsado. La idea es que este método sea invocado por la clase Boton cuando el usuario pulse el botón. Para que esto sea posible en algún momento hay que notificar al Boton quien es el Oyente que debe ser notificado. La clase Boton quedaría:
class Boton extends . . . {
    . . .
    private Oyente oyente;
    void registrarOyente(Oyente o) {
        oyente = o;
    }
    void click() {
        . . .
        oyente.botonPulsado(this);
    }
}
El método registrarOyente sirve para que alguien pueda 'apuntarse' como receptor de las acciones del usuario. Obsérvese que existe una referencia de tipo Oyente. A Boton no le importa que clase va a recibir su notificación. Simplemente le importa que implante la interface Oyente para poder invocar el método botonPulsado. En el método click se invoca este método. En el ejemplo se le pasa como parámetro una referencia al propio objeto Boton. En la realidad lo que se pasa es un objeto 'Evento' con información detallada de lo que ha ocurrido.
Con todo esto la clase que utiliza este mecanismo podría tener el siguiente aspecto:
class miAplicacion extends . . . implements Oyente {
    public static main(String [] args) {
        new miAplicacion(. . .);
        . . .
    }
     . . .
    miAplicacion(. . .) {
        . . .
        Boton b = new Boton(. . .);
        b.registrarOyente(this);
    }

    . . .
    void botonPulsado(Boton x) {
        // procesar click
        . . .
    }
}
Obsérvese en el método registrarOyente que se pasa la referencia thisque en el lado de la clase Boton es recogido como una referencia a la interface Oyente. Esto es posible porque la clasemiAplicacion implementa la interface Oyente . En términos clásicos de herencia miAplicacion ES un Oyente .








No hay comentarios:

Publicar un comentario