Pages

Subscribe:

Entradas



Clases abstractas


18.1. 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.

18.2. 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.

18.3. 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.

Antonio Bel Puchol - antonio@abelp.net

Encapsulamiento en Java



Anteriormente hemos hablado del encapsulamiento sin ahondar mucho en el tema. En este artículo vamos a profundizar un poco más.

Imaginemos que se crea una clase, una docena de programadores tienen acceso a dicha clase y la utilizan a discreción, posteriormente dicha clase comienza a comportarse de una manera inesperada debido a que los valores que algunas variables han tomado no fueron anticipados y todo comienza a desmoronarse. Para corregir el problema se crea una versión más nueva de dicha clase y listo.

Bueno, a esto le llamamos flexibilidad y capacidad de mantenimiento, ambas son características y beneficios de la programación Orientada a Objetos (OO) pero para que una clase pueda cumplir dichas funciones los programadores debemos de hacer algo. Imaginemos que creamos una clase con variables de instancia públicas a las cuales podemos acceder sin problemas desde fuera de la misma clase...

public class MiClase{
public int tipo;

}


class AccesoDirecto{

public static void main(String[] args){

MiClase mc = new MiClase();


mc.tipo = -5; //1

}
}


Analizando el código anterior podemos darnos cuenta de que las variables enteras tipo y clase son públicas y pueden ser accedidas directamente a través de una instancia de la clase MiClase, esto compila sin ningún problema, digamos que es 'legal', sin embargo, ¿qué pasa si ingresamos un valor que no se supone debe de tener una variable (en este caso el -5 que le asignamos a tipo)?, simplemente no hay nada que nos detenga para hacerlo. La única manera de proteger el código es escribiendo un método que nos permita regular los valores que cada variable puede tener y escondiendo las variables para que no se pueda acceder a ellas de manera directa, esto es el principio básico de encapsulamiento.

Si se desea flexibilidad, buen mantenimiento y extensibilidad, nuestro diseño en el código debe de incluir encapsulamiento, para ello debemos de hacer lo siguiente:

* Mantener las variables de instancia protegidas (puede ser con un modificador de acceso, p.ej., private)
* Hacer métodos de acceso públicos para forzar al acceso a las variables por medio de dichos métodos en lugar de acceder directamente.
* Utilizar las convenciones de código para los nombres de los métodos, p. ej., set y get.

El ejemplo anterior modificado para un buen encapsulamiento quedaría así:

public class MiClase{
private int tipo;

public void setTipo(int t){
tipo = t;
}


public int getTipo(){

return tipo;

}

}


class AccesoIndirecto{


public static void main(String[] args){
MiClase mc = new MiClase();

mc.setTipo(5);
System.out.println("El tipo es:" + mc.getTipo());

}


}


Si nos fijamos un poquito, en el método setTipo() no existen validaciones para prevenir que un valor no válido sea asignado a la variable, sin embargo, el proveer de un método de este tipo desde el diseño inicial de la aplicación nos permite posteriormente modificar el comportamiento de la misma sin afectar los métodos utilizados, tal vez en un futuro se desee que dicha variable solamente pueda tener uno entre un rango de valores y se podrán aplicar posteriormente los cambios sin que haya repercusiones negativas.

Esto es todo con respecto al encapsulamiento. ¿Alguna duda? deja tu comentario.

Más sobre programación en Java aquí.