Buscar
Social
Ofertas laborales ES
martes
may152001

Uso de las interfaces de Java


Buscando el por qué de los interfaces.


Fecha de creación: 15.05.2001

Revisión 1.0.1 (15.10.2002)

Alberto Molpeceres
al AT javahispano DOT org

Copyright (c) 2002, Alberto Molpeceres. Este documento puede ser distribuido solo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en /licencias/).



Introducción


Hace no demasiado tiempo fuí a una entrevista de trabajo como desarrollador Java. Como programador con relativa experiencia en Java pensaba que todo estaría bajo control en la parte técnica. Me equivoqué.


Una de las preguntas que me hicieron fue: ¿cuando usas interfaces y cuando herencia a la hora de diseñar software?. Realmente no me lo esperaba, hasta ahora para mi era una cuestión de intuición (al igual que para muchos otros) más que un tema racional. Solo acerté a a explicar las diferencias entre una cosa y otra, con los nervios ni tan siquiera me vino a la cabeza la mas conocida de todas las razones, la herencia múltiple, y mi interlocutor dijo que el también conocía el lenguaje, pero que quería saber el por qué.


Como tenía intención de cambiar de trabajo, quería preparame mejor para el resto de las entrevistas, y aunque fuera poco probable que me volvieran a hacer la misma pregunta, como cuestión personal, decidí buscar mi propia respuesta a este tema, y aquí estoy, contando lo que he encontrado.



Herencia.


Como he dicho antes, la primera y más conocida función del uso de interfaces es la de resolver el problema de la herencia múltiple presente en otros legunajes, como por ejemplo C++. Los interfaces de Java, al separar la forma del como (la declaración del código que lo implementa) permiten la herencia multiple sin los problemas típicos que se pueden plantear para decidir que implementación usar cuando una clase hereda de dos que tienen implementaciones distintas para la misma signatura de un método. Esta claro que tampoco es una solución mágica (simplemente no se herda el código, asi que no hay que decidir cual se coge), pero es una solucióón. Pero esta no podría ser la única razón para el uso de interfaces, ya que tampoco es la más usada (en realidad se usa bastante poco si exceptuamos componentes gráficos que implementan varios interfaces de oyentes de eventos). Además, los "manuales de la buena programación" dicen que los interfaces son para modelar las relaciones tiene un, no es un, aunque esto no siempre se así.


Polimorfismo.


Asi que me puse a pensar en las ocasiones en que yo he usado interfaces. La respuesta era fácil, cuando necesita cierto polimorfismo, es decir, cuando necesitaba que una clase pudiera tener con los mismos métodos o atributos distintos comportmientos, por ejemplo, una clase que pudiera almacenarse en una base de datos o en un fichero de texto sólo cambiando el objeto que la hace persistente. Siempre que todos implementen el mismo interface, la clase puede almacenarse en cualquier tipo de dispositivo sin cambiar los métodos necesarios. Algunos dirán que esto se podría hacer de la misma forma con algunas jerarquías de herencia, pero en mi opinión de esta forma el código es mucho más flexible a la hora de añadir funcionalidad a la aplicación (por no mencionar la de if que se quitan). Ya tenía dos razones.


Diseño.


Entonces, viendo el funcionamiento de algunos grandes proyectos caí en una tercera razón, que quizas tiene menos que ver con la programación en primera instancia, pero que es de enorme importancia para el diseño (para el buen diseño) de aplicaciones. Los interfaces de Java son (o pueden ser) el contrato entre distitnas partes de una aplicación, o entre los distintos programadores de una aplicación.


Si se discuten y diseñan unos buenos interfaces entre los distintos componentes de la aplicación en la primera parte del desarrollo, los diferentes grupos de trabajo pueden trabajar en paralelo sin tener que preocuparse de lo que hacen o ya han hecho el resto, y para los test es bastante facil escribir un par de clases de prueba que implementen esos interfaces. De esta forma, la intergración entre las distintas partes de la aplicación ya esta hecha desde un principio, sin tener que andar consultando de que métodos se dispone para llevar a cabo una labor, y los grupos de desarrollo se solo tienen que preocuparse de que la implementación de su parte sea el orgullo del proyecto ;-).


Además, el uso de interfaces, debido a la propia naturaleza de Java, hace que sea tremendamente fácil encontrar las clases que se ven afectadas por una cambio brusco en alguna parte de la aplicación, ya que lo hará el compilador sólo.



Conclusión


Y eso es todo lo que se me ha ocurrido (herencia, polimorfismo y diseño), por ahora me he quedado satisfecho, en la próxima entrevista ya tendré claro que contestar, pero espero que todo aquel que tenga nuevas ideas para el uso de interfaces me las haga llegar.



Recursos

Acerca del autor

Alberto Molpeceres
Alberto es es ahora mismo desarrollador de aplicaciones en ámbito cliente/servidor para la empresa T-Systems - debis Systemhaus en Munich (Alemania). Cuando no está trabajando o "metiendo caña" al resto de los integrantes de javaHispano intenta pasear con su novia, buscar la desaparecida lógica del idioma alemán o intentar olvidar la pesadilla que es buscar piso en Munich.

martes
may152001

Gráficos en Java (Parte 1)

Introducción al tratamiento gráfico: La clase Graphics.





En este artículo nos centraremos en conocer qué es y cómo trabaja la clase Graphics. Dicha clase, que pertenece al paquete java.awt es el sistema básico para todas las operaciones relacionadas con el uso de gráficos en Java y soporta un gran surtido de métodos posibilitándole al programador dibujar o colocar imágenes dentro de un componente. Veremos también las técnicas y métodos que se emplean para "pintar" y en el ejemplo mostraré algunas de las formas básicas que esta clase nos proporciona.



La clase Graphics.




La clase Graphics es el sistema básico de todas las operaciones gráficas por lo que parece fundamental que se entienda bien su concepto antes de ponernos a tratar gráficos o imágenes. Esta clase abstracta tiene la misión de conformar el contexto gráfico y la de proporcionar los métodos necesarios para poder dibujar en la pantalla.



El contexto gráfico.




Consiste en encapsular la información necesaria para las operaciones de renderizado básicas, es decir, toda la información que afecte a las operaciones de dibujado conforma el contexto gráfico y la salida a la ventana en la que se va a dibujar tiene que pasar por este contexto. Incluye las siguientes propiedades más importantes:





  • El objeto Component sobre el que se va a dibujar. Puede ser la ventana principal de un applet, de un frame o de una ventana hija.
  • Un origen de coordenadas. Se especifican en pixels y comienzan en la esquina superior izquierda (0,0). No obstante, recordar que las coordenadas son relativas a la ventana en la que estemos trabajando ya que la posición real que ocupa una ventana madre en la pantalla no tiene porqué ser la misma que la de una ventana hija que despleguemos en algún momento.
  • El "clipping". Esto no es más que una ventana (un rectángulo invisible) sobre el que vamos a poder pintar o renderizar nuestras imágenes. Todo lo que quede fuera será cortado (clipped).
  • Los colores del fondo y el primer plano (backgroun y foreground). Por defecto son negro y blanco respectivamente.
  • La fuente de texto. Por defecto es la fuente Dialog, estilo plano y 12 pulgadas.




Pero para dibujar, nuestro programa necesita un contexto gráfico válido que vendrá dado a través de una instancia o ejemplar de la clase Graphics. El problema es que al ser una clase abstracta, ésta no se puede instanciar directamente por lo que lo que habrá que hacer es pasarle el contexto al programa a través de los métodos paint() o update() o bien, que el programa obtenga el contexto mediante el método getGraphics() de la clase Component().




En este artículo nosotros obtendremos una instancia de la clase Graphics a través de los métodos paint() o update().



Los métodos




Graphics nos debe proporcionar todos los métodos necesarios para poder dibujar formas básicas, texto con todas las fuentes que tiene el sistema así como permitirnos cargar imágenes. Todo lo que portemos a la ventana de renderizado se hará a través de estas funciones.



paint(), repaint() y update().




Estos 3 métodos son los encargados de mostrar los gráficos. Java nos proporciona una versión por defecto en la clase Component por lo que tendremos que sobrecargar update() y paint() para que nuestro programa pinte lo que deseemos y como queramos.




Cuando el usuario llama al método repaint() de un componente, el AWT (recondando que Swing es "algo asi" como una extensión de AWT) llama al método update() de ese componente, que por defecto llama al método paint().



paint().




Su sintáxis es:




public void paint(Graphics g)



Es el responsable de dibujar las imágenes. Normalmente es el sistema operativo el que lo llama al dibujar la ventana por primera vez, volviéndolo a llamar cada vez que entiende que la ventana o una parte de ella debe ser redibujada (por ejemplo, por haber estado tapada por una ventana y quedar de nuevo a la vista). Esta llamada la hace a través del método update().



update().




Su sintáxis es:




public void update(Graphics g)




Este método se llama en respuesta a una solicitud por parte del método repaint(), por el AWT o por el programador cuando ha realizado un cambio en la ventana de renderización y necesita que se dibuje de nuevo.




La implementación por defecto trabaja "borrando" la escena actual mediante un repintado del mismo color que el de background y luego llama al método paint() para pintar la nueva escena. Esta técnica provoca el molesto efecto llamado parpadeo (flickering) el cual se puede solucionar redefiniendo el método update() de manera que solo actualice la zona de pintado donde se han hecho modificaciones, o bien, como veremos en un artículo posterior, empleando la técnica del doble buffer.



repaint().




Su sintáxis es:




public void repaint()
public void repaint(long tm)
public void repaint(int x, int y, int w, int h)
public void repaint(long tm, int x, int y, int w, int h)



Este método solicita que un componente sea repintado llamando lo más pronto posible al método update() del componente. De las posibles sintáxis que disponemos se extrae que el repintado puede ser inmediato, transcurrido un tiempo (mseg) o repintar solo la zona rectangular especificada en los parámetros. Esta última técnica es de gran utilidad cuando el repintado de la escena consume mucho tiempo, así solo repintamos la franja que se haya modificado.




Para reducir el tiempo que se tarda en repintar, el AWT toma dos técnicas:





  • Repintar solo aquellos componentes que necesitan repintarse, bien porque se han cubierto por otro componente o bien porque el programador así lo solicitó.
  • Si un componente se tapa parcialmente por otro, cuando se le devuelve a primer plano, solo se repinta la zona cubierta.



Redibujar en Swing.




Todo lo dicho anteriormente necesita ser ligeramente corregido en caso de trabajar con componentes Swing, es decir, si vamos a pintar sobre un JFrame o un JApplet. Esto se debe a que estas dos clases definen su propio método update(Graphics g) pero éste lo que hace es tan solo llamar al método paint(), es decir, no limpia la pantalla cada vez que se necesita repintar la escena como ocurría con AWT. Se hace por tanto necesario sobrecargar este método como se puede ver en el ejemplo.



Poniéndolo todo junto.




En el siguiente ejemplo se muestran algunas de las primitivas gráficas que la clase Graphics incorpora. No las comento en el artículo porque su sintáxis es sencilla. La explicación de todas y cada una de ellas lo puedes encontrar en las especificaciones HTML del API de Java.




Así mismo, seguiremos el movimiento del ratón por la ventana de pintado para ver cómo actua el método repaint() y cómo implementar un método update() que reduzca lo más posible el parpadeo (flickering) (aunque cada problema requerirá su solución particular).




//Fichero FormasBasicas.java

/*
<applet code = "FormasBasicas" width = 600 height = 300>
</applet>
*/

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JApplet;

public class FormasBasicas extends JApplet implements MouseMotionListener {

Dimension d;
int coordX[] = {250,350,330,350,250,270,250};
int coordY[] = {100,100,125,150,150,125,100};
int puntos = 7;
//variables para almacenar la posición actual del mouse
int posX = 0, posY=0;
//variables para recordar la posición anterior del mouse
int memX = 0, memY=0;

public void init() {
d = this.getSize();
addMouseMotionListener(this);
}

public void mouseDragged(MouseEvent me) {}

public void mouseMoved(MouseEvent me) {
this.showStatus("Coordenadas en : " +me.getX() + ", " + me.getY());
posX = me.getX();
posY = me.getY();
this.repaint();
}

/*
En esta implementación de update() trato de "disimular" el flickering, para
ello voy borrando el rastro que va dejando el mouse repintándolo de blanco.
*/

public void update(Graphics g) {
g.setColor(Color.black);
g.drawLine(0,posY,d.width-1,posY);
g.drawLine(posX,0,posX,d.height-1);
g.setColor(Color.white);
if (memY != posY) {
g.drawLine(0,memY,d.width-1,memY);
memY = posY;
}
if (memX != posX) {
g.drawLine(memX,0,memX,d.height-1);
memX = posX;
}
g.setColor(Color.black);
this.paint(g);
}

/*
Este es el update() básico, como trabaja en el AWT, solo que lo he
implementado porque estoy trabajando con Swing. Juega con ambos para
que observes la diferencia y lo molesto que puede llegar a ser el parpadeo.
*/

/*public void update(Graphics g) {
g.setColor(Color.white);
g.fillRect(0,0,d.width-1,d.height-1);
g.setColor(Color.black);
g.drawLine(0,posY,d.width-1,posY);
g.drawLine(posX,0,posX,d.height-1);
this.paint(g);
}*/

/*
Aquí pintamos todas las figuras. Observa que al pasar por las figuras
sólidas las líneas que nos señalan la posición del ratón parpadean y/o
desaparecen. Podríamos haber puesto todo este código dentro del método
update() y haber reducido aun más el efecto del parpadeo.
*/
public void paint(Graphics g) {
g.drawRect(0,0,d.width-1,d.height-1);
g.drawLine(10,10,110,60);
g.setColor(Color.green);
g.fillRect(130,10,100,50);
g.setColor(Color.orange);
g.drawRoundRect(250,10,150,50,20,20);
g.setColor(Color.blue);
g.fillArc(10,100,100,50,90,270);
g.setColor(Color.magenta);
g.drawOval(130,100,100,50);
g.setColor(Color.red);
g.fillPolygon(coordX,coordY,puntos);
g.setColor(Color.gray);
g.drawString("Linea",10,80);
g.drawString("Rectangulo sólido",130,80);
g.drawString("Rectángulo redondeado",250,80);
g.drawString("Arco sólido",10,170);
g.drawString("Elipse",130,170);
g.drawString("Un poligono propio",250,170);
g.drawString("Este texto queda cortado", d.width-60,170);
}
}




  • Puedes conseguir el código fuente de este artículo aquí: código
  • Si tienes instalado el plug-in de Java2 en tu ordenador puedes comprobar el applet aqui: applet



Próximo artículo




A partir del próximo artículo nos meteremos a estudiar el API Java 2D empezando por la clase Graphics2D. Si bien este artículo es introductorio al tratamiento de gráficos, la clase Graphics2D extiende de la clase Graphics por lo que rápidamente se deduce que es más potente. Es por ello que a partir de ahora trabajaremos con esta última.
















Leo Suarez es un Ingeniero Superior de Telecomunicaciones por la
Universidad de Las Palmas de Gran Canaria con todas sus letras, que no
son pocas, y trabaja como tal en Santa Cruz de Tenerife.
Cuando no
está saltando de isla en isla o escribiendo para javaHispano aprovecha
para disfrutar con la novia y los amigos del estupendo clima de las islas afortunadas.

Para cualquier duda o tirón de orejas, e-mail a:
leo_ARROBA_javahispano.com




martes
may152001

Mapeo de XML a Java (Parte 1)


Mapeo de XML a Java (parte 1)


Fecha de creación: 15.05.2001

Revisión 1.0.1 (15.10.2002)

Alberto Molpeceres
al AT javahispano DOT org

Copyright (c) 2002, Alberto Molpeceres. Este documento puede ser distribuido solo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en /licencias/).



Introducción


En este articulo se plantea una introducción, totalmente funcional, a la lectura de ficheros XML y su mapeo a clases de Java con el SAX (Simple Api for Xml). Asi mismo, se explicara por que en muchas ocasiones este API es superior al DOM (Document Object Model), aunque su manejo pueda resultar mas confuso.


En este articulo dejaremos de lado (de momento) bastantes aspectos relacionados con la manipulacion de XML desde Java, como pueden ser los distintos tipos de parsers y funciones avanzadas, como la validacion.


Asi mismo, se supone un cierto conocimiento de XML, su estructura y su funcion, ya que no se explicara en este articulo.



APIs: SAX vs DOM


Pasar un fichero XML a clases de Java es un proceso de parsing, hay que leer y procesar todo el fichero para hacerlo, por lo que si tenemos que leer gran cantidad de XML nos comeremos la memoria del sistema de forma rapida, recordando que como todos los procesos de parsing, no es un proceso rapido.


Aqui tengo que recordaros, que tanto SAX somo DOM son dos APIs, no dos parsers, son dos ideas de como afrontar un problema, y son muchos los parsers existentes (ver recursos) que implementan estas APIs. Tambien existe una version de DOM optimizada para Java, llamada JDOM, pero su funcionamiento es muy similar al DOM.


Quizas el API mas usado sea el DOM, pero no por ello es el mejor. El DOM lee todo el contenido del fichero de una pasada, y crea en memoria una estructura jerarquica en forma de arbol que representa el fichero y que luego puede usarse para hacer el mapeo a clases de Java. La primera de las desventajas es clara, se ha de crear la imagen de los datos en memoria, por lo que si es muy grande puede ocupar mucho espacio, con una gran cantidad de pequeños elementos, cuyo control, recorrido y manipulacion requieren aun mas memoria y tiempo. Pero sus desventajas van mas alla, ya que se han de recorrer los datos en varias ocasiones, la primera para cargar la imagen en memoria y despues varias veces para sacar la infomacion necesaria para nuestra aplicacion.


SAX no trabaja asi. SAX extrae la informacion para nuestra aplicacion segun procesa el fichero, sin crear ninguna estructura adicional en memoria mas que la extrictamente necesaria para la lectura del fichero. SAX trabaja respondiendo a eventos, eventos que se producen al procesar el fichero XML, como pueden ser el fin o principio del documento, el fin o principio de un elemento, etc. Al hacer todo el proceso en una sola pasada obtenemos un mejor rendimiento.


Por supuesto no quiero decir que el API DOM no sirva para nada, nada mas lejos de la realidad, solo digo que en mi opinion no es el mas apropiado para realizar el mapeo entre documentos XML y Java. Si tu aplicación requiere de algun tipo de manipulacion del documento XML, como por ejemplo para combinar varios o aplicar una hoja de estilo, entonces DOM (o el mas moderno JDOM) es tu API, SAX no esta pensado para eso. Sax no vale para eso.


Un parser.


Bueno, lo primero de todo es conseguir un parser real, uno que implementa SAX (normalmente los parser de XML pueden trabajar con SAX y DOM). Yo os dire el parser con el que trabajo, libre, gratis y bueno, pero vosotros podeis trabajar con otro si quereis, cambiaran algunas clases, las especificas del parser, pero en general será el mismo esquema.


El parser que yo utilizo es el Xerces para Java de Apache, podeis bajarlo desde su pagina[1], alli podeis conseguir el parser (para varios lenguajes de programacion) y otras herramientas Java para trabajar con XML.


El interface ContentHandler.


Este interface es el centro de todo proceso de XML con SAX. Es el que define todos los eventos que se producen a los largo del proceso del documetno, asi que como habreis adivinado, vuestras clases de proceso de XML deberan implementar este interface para que el parser haga lo que vosotros necesitais.


Antes de ver todos los metodos que tiene este interface, puede ocurrir que vosotros no los necesiteis todos, quizas solo necesitais unos pocos, asi que como siempre, para ahorrar esfuerzo, existe una clase que ya implementa este interface, como siempre, pero con los metodos vacios para que solo tengais que extenderla y sobreescribir los que os hagan falta. Esta clase se llama DefaultHandler. Los metodos del interface ContentHandler los veremos en el proximo articulo, asi como otras cosas mas avanzadas, para evitar que este se haga demasiado grande.


Como hemos dicho, el API SAX se basa en eventos, eventos que se producen al procesar el fichero, del estilo de inicio/fin del documento, inicio/fin de un elemento, datos entre tags, etc, asi pues los metodos de ContentHandler son del estilo startDocument, endDocument, startElement, endElement, characters, etc, que se ejecutaran cuando oucrre dicho suceso.


Veamos un ejemplo básico.


El ejemplo.


Supongamos que tenemos el siguiente sencillo documento XML para almacenar nuestras paginas web favoritas:



<?xml version="1.0"?>
<favoritos>
<pagina valoracion="10" >
<nombre> javaHispano lt;/nombre>
<direccion> http://www.javahispano.org lt;/direccion>
</pagina>
<pagina valoracion="1" >
<nombre> GFT Techonologies </nombre>
<direccion> http://www.gft.com </direccion>
</pagina>
</favoritos>



Obviamente necesitaremos una clase que albergue los datos de nuestros favoritos:



public class Pagina
{

private String nombre;
private String direccion;
private int valoracion;

public Pagina ()
{
}

public void setNombre (String nombre)
{
this.nombre = nombre;
}

public String getNombre()
{
return nombre;
}

// y demas metodos similares
. . .

}



Suponiendo que queramos guardar todos los favoritos leido en un "Vector" tendremos que sobreescribir los metodos que nos interesan de la clase DefaultHandler.


En este caso seran :


  1. El constructor, para que acepte el Vector donde almacenar los elementos que leemos.



  2. El metodo startElement, para que detecte cuando empieza un nuevo "favorito".



  3. El metodo endElement, para que detecte el final de los elemetnos "nombre" y "direccion" para asi poder coger su valor.



  4. El metodo characters, que recoge los valores contenidos entre las distintas etiquetas de inicio y fin de un elemento.


Métodos más importantes de ContentHandler


Ahora solo explicare los parametros y metodos estrictamente necesarios para el ejemplo, una descripcion mas detallada de todos los metodos y sus parametros de el interface ContentHanlder la daré en el siguiente articulo.


Veamos nuestro Handler:

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import java.util.Vector;

public class MiXMLHandler extends DefaultHandler
{

//vector de instancias
private Vector instancias;
//"Pagina" que se esta procesando
private Pagina actual;
//valor contenido entre las etiquetas de un elemento
private String valor;

public MiXMLHandler (Vector v)
{
instancias = v;
}

/*
localName: contiene el nombre de la etiqueta.
att: de la clase "org.xml.sax.Attributes", es una tabla que contiene
los atributos contenidos en la etiqueta.
*/
public void startElement( String namespaceURI, String localName, String qName,
Attributes attr ) throws SAXException
{
//comprobamos si empezamos un elemento "pagina"
if (localName.equals("pagina")){
//creamos una nueva pagina y la añadimos al vector
actual = new Pagina ();
instancias.addElement (actual);
//y le asignamos la "valoracion" contenida como atributo
actual.setValoracion (Integer.parseInt(atts.getValue("valoracion")));
}
}

public void endElement (String namespaceURI, String localName, String rawName)
throws SAXException
{
/*
miramos de que elemento se trata y asignamos los atributos
correspondientes a la "Pagina" actual segun el contenido del elemento
recogido en "valor" por el metodo characters.
*/
if (localName.equals("nombre")){
actual.setNombre (valor);
}
else if (localName.equals("direccion")){
actual.setDireccion (valor);
}
}


/*
Los parametros que recibe es la localizacion de los carateres del elemento.
*/
public void characters (char[] ch, int start, int end) throws SAXException
{
//creamos un String con los caracteres del elemento y le quitamos
//los espacios en blanco que pueda tener en los extremos.
valor = new String (ch, start, end);
valor = valor.trim();
}

}



Y eso es todo, esa es la clase que procesara nuestro fichero XML, pero por supuesto en algun sitio tendremos que decirle al parser que fichero procesar y que tiene "DataHandler" utilizar, ¿no?. Ahora vamos con ello.

import java.util.Vector;

import org.xml.sax.XMLReader;
import org.xml.sax.SAXException;

import org.apache.xerces.parsers.SAXParser;

public class Test
{
Vector instancias = new Vector ();

public Test()
{
}

public void procesarFichero ()
{
try
{
/*
puede paracer un lio mezclar "SAXParser" y "XMLReader", pero solo es
un problema de nomenclatura entre versiones. Se usa un SAXParser,
que implementa el interface XMLReader (todos los parsers de XML lo
hacen), porque en la version 1 de SAX ya se uso el termino "parser",
y se mantiene por convencion.
*/
XMLReader parser = new SAXParser();
//añadimos al parser nuestro "ContentHandler", pasandole el vector de instancias.
parser.setContentHandler(new MiXMLHandler(instancias));
//y le decimos que empieze a procesar nuestro fichero de favoritos
parser.parse("misFavoritos.xml");
}
catch (Exception e)
{
System.out.println ("Error al procesar el fichero de favoritos: " + e.getMessage());
e.printStackTrace();
}
}


public static void main(String[] args)
{
Test test = new Test();

test.procesarFichero();
}
}



Y eso es todo, sencillo, ¿no?. Ahora podemos usar ese vector de instancias para lo que queramos, como por ejemplo, asegurarnos de que nuestro parser trabaja bien ;-).


El proximo capitulo.


En el proximo articulo explicare mas en detalle el interface ContentHandler, y si tengo tiempo explicare que hacer cuando tenemos documentos XML "recursivos" en los que aparece la misma etiqueta en elementos anidados, como por ejemplo ocurre con nombre en el siguiente documento:

<?xml version="1.0"?>
<clientes>
<empresa>
<nombre> GFT Technologies </nombre>
. . .
<persona-contacto>
<nombre> Alberto Molpeceres </nombre>
. . .
</persona-contacto>
</empresa>
</clientes>




Conclusión


Como hemos visto, el uso de SAX para procesar archivos XML no es ni mucho menos difícil. El API SAX permite de forma sencilla y rápida obtener objetos Java a partir del XML



Recursos




[1] ,
http://xml.apache.org/xerces-j/


Acerca del autor

Alberto Molpeceres
Alberto es es ahora mismo desarrollador de aplicaciones en ámbito cliente/servidor para la empresa T-Systems - debis Systemhaus en Munich (Alemania). Cuando no está trabajando o "metiendo caña" al resto de los integrantes de javaHispano intenta pasear con su novia, buscar la desaparecida lógica del idioma alemán o intentar olvidar la pesadilla que es buscar piso en Munich.

martes
may152001

Patrones de Software (Parte 1)


Diseño de software con patrones.


Fecha de creación: 15.05.2001

Revisión 1.0.1 (15.10.2002)

Alberto Molpeceres
al AT javahispano DOT org

Copyright (c) 2002, Alberto Molpeceres. Este documento puede ser distribuido solo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en /licencias/).



Introducción


En esta serie de artículos (me temo que no entrará en uno), intentaré plantearos una iniciación al mundo del diseño de software con patrones. Quede claro de antemano que los patrones que aquí explique, ni son los únicos, ni son todos los que hay, no todos los autores les dan los mismos nombres, e incluso quizas no sean los mejores, pero en fin, son los que yo explicaré porque son los yo que conozco.


En este primer artículo, perdonadme si me excedo con la parte literaria y no entro a lo bestia con el asunto, pues intentaré simplemente que os entre el gusanillo por esta historia y que tengais cierto interés en posteriores entregas.



¿De dónde salen los patrones del software?


Aunque los patrones son algo más viejo, y su origen es aplicable a otras personas (de hecho al arquitecto Christopher Alexander que los aplicó a la arquitectura en los años 70), solo os contaré por qué se han vuelto tan famosos", y por qué al hablar de patrones todo el mundo menciona una cosa llamada la pandilla de los cuatro (Gang of Four) o GoF.


El reciente interés del mundo del software por los patrones tiene su origen, o mejor dicho, su explosión a partir de 1995, tras la aparición y el éxito del libro Design Patters: Elements of Reusable Object-Oriented Software
[1] de la pandilla de los cuatro. Ellos, Erich Gamma, Richar Helm, Ralph Johnson y John Vlissides, se dedicaron a recopilar una serie de patrones (hasta 23) aplicados habitualmente por expertos diseñadores de software orientado a objetos, y al hacerlos públicos... la fiebre estalló, pero como os he dicho, ni son los inventores, ni son los únicos implicados, solo les menciono porque es realmente imposible leer algo sobre patrones y no hacerlo sobre la GoF.


Por último mencionaré a Craig Larman, que es uno de los autores mas interesantes que he encontrado sobre el tema, que ha definido de los patrones GRASP[2] (patrones generales de software para asingar responsabilidades), los cuales mencionaré también aquí.


Dos conceptos clave.


Creedme si os digo que ahora, de verdad, quería empezar con el tema de los patrones, pero me temo que no es posible hacerlo sin aclarar dos términos que aparecerán en muchas ocasiones y que son un objetivo permanente del diseño orientado a objetos, como son la cohesión y el acoplamiento, que aunque estoy seguro de que muchos de vosotros conocereis, los volveré a explicar por si tenemos algún rezagado.


Podriamos definir la cohesión de una clase (o de un paquete, o de lo que sea) como la relación entre los distintos elementos de la clase, normalmente sus métodos. ¿En cristiano?, pues la cohesión dice que todos los elementos de una clase tiene que trabajar en la misma dirección, es decir, hacia un mismo fin. Por ejemplo, una clase Coche deberia ocuparse de cosas relacionadas con el coche en si, como acelerar y frenar, pero no de cosas ajenas a él como manipular información referente a su seguro. Como os habreis dado cuenta, la cohesión es una medida relativa, en el sentido de que depende de lo que cada uno piense que es la función de la clase, pero lo importante es mantener una cohesion lo más alta posible. Existen diferentes tipos de cohesión (funcional, secuencial, etc), pero creedme si os digo que eso ahora mismo no es importante.


Respecto al acoplamiento, se podría decir que es la interdependecia existente entre dos clases, paquetes, etc. Esto ocurre normalmente cuando una clase (o paquete) necesita saber demasiados detalles internos de otra para su funcionamiento, es decir, rompe el encapsulamiento del que tanto se habla en la programación orientada a objetos. También existen diversos tipos de acoplamiento (funcional, de datos, etc.), pero al igual que ocurría con la cohesión, eso no nos importa ahora, no es el obejtivo de estos artículos. Por supuesto, para tener un diseño correcto, fácil de mantener y modular, cuanto más bajo acoplamiento haya entre las clases (o paquetes), pues mejor.


Introducción a los patrones del software.


Seguro que en los últimos tiempos habreis oido muchas veces el término patrones del software, pero ¿qué son realmente estos famosos patrones?. Los patrones de software no son más que un conjunto de literatura sobre la resolución de problemas habituales en el diseño de software orientado a objetos.


Esta literatura que recoge los patrones empezó teniendo una forma fija, de forma que se existía una especie de plantilla fija (siguiendo el estílo indicado por la GoF), con secciones tales como motivación, explicación, etc, que debía ser rellenada. Algunos autores han desarrollado sus propias plantillas o formato para los patrones, y otros simplmente optan por una descripción más relajada basada en textos sencillos sin orden preestablecido. Yo seguiré esta última aproximación, de forma que debereis referioros a los libros de la bibliografía para encontrar su definición formal.


En fin, volvamos al asunto, una definicion mas formal de lo que es un patrón podria ser:



Un patrón es una solución de diseño de software a un problema, aceptada como correcta, a la que se ha dado un nombre y que puede ser aplicada en otros contextos.


No penseis que son algo mágico, no lo son, y seguro que muchos de vosotros ya habeis utilizado muchos de ellos o con algunas pequeñas diferencias, aunque no supierais que era un patrón ya definido. Como ya he dicho, los patrones son simplemente una manera de resolver problemas del desarrollo del software, fruto de la experiencia, y por esa misma razón, con un poco de experiencia, creedme que no demasiada para algunos, podeis haber llegado a soluciones similares en algunos casos.


Y por fin, para terminar por hoy, para que no os quejeis, os dejo con el primer patrón.


El patrón Singleton.


El singleton es, posiblemente, el patrón más sencillo que existe. Trata las situaciones en las que solo se permite una instancia de una clase dada.


Veamos un ejemplo, tenemos una clase Coche que representa uno de estos coches modernos, controlado totalmente por computador. Este coche esta compuesto de muchos elementos, como por ejemplo el motor, que se compone a su vez de otros, hasta que llegamos a un nivel dado, por ejemplo al séptimo. ¿Qué sucede si un elemento de ese nivel, por ejemplo un termostato en las válvulas tiene que dar un mensaje a la clase Coche?, como por ejemplo, para decirle que muestre un indicador en el cuadro de mandos avisando de una temperatura elevada.


Podriamos ir pasando la referencia al Coche de un nivel a otro, pero eso se hace impracticable, por lo que a veces es conveniente una visibilidad global (aunque pueda implicar un acoplamiento de paquetes, por ejemplo), usando para ello el patrón Singleton, que se asegura de que se producirá una sola instancia de Coche y de que esta podrá ser recuperada en cualquier momento por un metodo de clase, en Java, static.

final class Coche {
/* la única instancia de coche que se permitirá.
No es obligatorio crear el Singleton estáticamente,
se podría proveer un metodo que lo cree
*/
private static Coche c = new Coche();

// atributos
private Motor motor = new Motor();
. . .

//constructor privado para que no se pueda instancia
private Coche(){
//vacío porque creamos la instancia estáticamente
}

// metodo que devuelve el "singleton" Coche
public static Coche getCoche () {
return c;
}

// resto de metodos
public void acelerar() {
// implementación del metodo
}

. . .

}



Como hemos dicho, solo debe haber una instancia del Singleton. por ello el contructor privado, que aunque al ser el singleton una estancia estática no se producirán más instancias, si podría ocurrir que se creen (o se reinicialicen) las clases que contiene, en este caso el motor. También tenemos que asegurarnos de que no se derive la clase, por ello el modificador de clase final.


También habría que tener en cuenta otras operaciones que crean instancias en Java, como por ejemplo el método clone, por lo que habría que sobreescribirlo para que lanzase una excepción o simplemente devolviese la instancia ya existente.



Conclusión


Pues eso es todo por hoy, como habreis visto esto de los patrones no es nada apto solo para gurus, pero tampoco os penseis que todos son como el pobre Singleton, alguno mas interesante ya veremos, pero no ahora. En el próximo explicaré un par de patrones más, el experto y el creador supongo.



Recursos




[1]
Design Patters: Elements of Reusable Object-Oriented Software,
Erich Gamma, Richar Helm, Ralph Johnson y John Vlissides,
Addison Wesley, 1994




[2]
UML y Patrones: Introducción al análisis y diseño orientado a objetos,
Craig Larman,
Prentice Hall, 1999.


Acerca del autor

Alberto Molpeceres
Alberto es es ahora mismo desarrollador de aplicaciones en ámbito cliente/servidor para la empresa T-Systems - debis Systemhaus en Munich (Alemania). Cuando no está trabajando o "metiendo caña" al resto de los integrantes de javaHispano intenta pasear con su novia, buscar la desaparecida lógica del idioma alemán o intentar olvidar la pesadilla que es buscar piso en Munich.

lunes
may142001

Tomcat 4 beta 5, la nueva versión de Tomcat sigue

La nueva versión de nuestro querido Tomcat sigue depurándose y corrigiendo "sin prisa pero sin pausa" todos los fallos de seguridad que se le van encontrando hasta llegar a ser tan aclamada y estable como la serie 3. Cuatro días después de la beta 4 ya salen los nuevos parches.