miércoles, 30 de mayo de 2012

4.2 Clases Abstractas

Clases abstractas

Concepto

Hay ocasiones, cuando se desarrolla una jerarquía de clases en que algún 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 geométricas. Podríamos pensar en tener una clase genérica, que podría llamarse FiguraGeometrica y una serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc. Podría haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase genérica FiguraGeometrica, porque esta clase representa una abstracción del conjunto de figuras posibles.

Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un método abstracto es un método declarado en una clase para el cual esa clase no proporciona la implementación (el código). Una clase abstracta es una clase que tiene al menos un método abstracto. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte también en clase abstracta.


Declaración e implementación de métodos 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 declaración. Los métodos abstractos se declaran también con el mismo modificador, declarando el método pero sin implementarlo (sin el bloque de código encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los métodos abstractos de la clase base (en el ejemplo el método dibujar) el compilador genera un error indicando que no se han implementado todos los métodos 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 ningún 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 implementación y encaja bien con la idea de que algo abstracto no puede materializarse.

Sin embargo utilizando el up-casting visto en el capítulo dedicado a la Herencia si se puede escribir:

FiguraGeometrica figura = new Circulo(. . .);

figura.dibujar();

La invocación al método dibujarse resolverá en tiempo de ejecución y la JVM llamará al método de la clase adecuada. En nuestro ejemplo se llamará al método dibujarde la clase Circulo

Código 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);
    }
}



La Clase anterior es idéntica aquella definida en el ejemplo de Polimorfismo, sin embargo, la Clase Base de Instrumento fue definida como abstract, algunos detalles de esta definición :

· Nótese que los métodos definidos como abstract no contienen ningún tipo de código dentro de ellos, inclusive no declaran ni llaves ({ }).

· Cuando es definido más de un método como abstract, es necesario que la Clase como tal sea definida también como abstract.

La característica de hacer una Clase/Método abstract reside en que no puede ser generada una instancia de la misma, este comportamiento se demuestra en el método principal (main)

· Aunque dentro del método sea generado un Arreglo de esta Clase abstracta, recuerde que un arreglo es únicamente un contenedor de Objetos, esto permite que sea generado sin ningún error.

· Dentro de comentarios se encuentra la generación de una instancia del tipo Instrumento la cual generaría un error al ser compilada la Clase.

No hay comentarios:

Publicar un comentario