domingo, 31 de octubre de 2010

Patrón de diseño: Adaptador

Saludos a todos.

Ahora hablaremos sobre otro patrón de diseño que puede ser utilizado en Java, que de hecho, hasta en su propia API se ha incluido para el manejo de eventos de interfaces gráficas. Estoy hablando acerca del patrón de diseño: Adaptador.

Si, como su nombre lo indica, trata de adaptar una clase para que no implemente todos los métodos declarados en una interfaz, esto lo hace, usando una clase que ya la interfaz en cuestión y la clase que utiliza la adaptadora debe sólo implementar en método que necesite o requiera, vamos a ver si con ejemplos me entienden mejor:

En java.awt.event se encuentra la interfaz MouseListener, esta interfaz contiene los métodos que sirven para manejar eventos del ratón:
void mouseClicked(MouseEvent e)
void mouseEntered(MouseEvent e)
void mouseExited(MouseEvent e)
void mousePressed(MouseEvent e)
void mouseReleased(MouseEvent e)

Supongamos que nosotros queremos que nuestra clase sólo implemente el evento mouseClicked, si implementamos esta interfaz en nuestra aplicación debemos también implementar los métodos declarados y por lo tanto colocar los demás métodos (mouseEntered, mouseExited, mousePressed y mouseReleased) y dejarlos vacíos (por regla de java en cuanto a que implemento la interfaz).

Con la clase adaptadora eso sería más fácil, yo puedo hacer extender (heredar) mi clase a MouseAdapter. Este clase MouseAdapter, implementa a la interfaz MouseListener y contiene implementado todos los métodos del Listener (aunque vacío, no importa), por lo tanto al heredar sólo sobreescribo el método que necesito. La limitante es que como Java no soporta herencia múltiple, si mi clase ya extiende de otra clase no puedo utilizar la clase adaptadora y me veré obligado a utilizar el Listener requerido.

Veamos código:
Implementando la interfaz me obliga a implementar todos métodos, aunque no los utilice:


package patronesdisenio.adaptador;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class MiClaseImplementada
implements MouseListener {
//La interfaz me obliga a implementar
//todos los métodos
@Override
public void mouseClicked(MouseEvent arg0) {}
@Override
public void mouseEntered(MouseEvent arg0) {}
@Override
public void mouseExited(MouseEvent arg0) {}
@Override
public void mousePressed(MouseEvent arg0) {}
@Override
public void mouseReleased(MouseEvent arg0) {}
}


La clase adaptadora me permite implementar sólo el método que deseo, aunque si mi clase ya extiende de otra clase, no podría utilizarla:



package patronesdisenio.adaptador;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JOptionPane;

public class MiClaseAdapter extends MouseAdapter {

@Override
public void mouseClicked(MouseEvent e){
JOptionPane.showMessageDialog(
null, "Hizo click en un elemento");
}
}


Esto es un ejemplo dentro del API de java, pero igualmente podría adaptarse a nuestro sistema, en caso de que no necesitemos implementar todos los métodos de una interfaz.

Patrón de diseño: Singleton

Saludos a todos. Hoy comenzaremos con el primer artículo acerca de los patrones de diseño. Para hoy hablaremos acerca del patrón de diseño Singleton.

Recuerdo en mi primer curso de Java, cuando nos asignan realizar un proyecto en este lenguaje, utilizando las ventajas de javax.swing, es decir interfaces gráficas, nuestro grupo creó un menú que llamaba a ventanas o diálogos. Se nos presentó el siguiente problema: Cuando se llamaba a una opción de menú se desplegaba una ventana auxiliar nueva, si de nuevo haciamos click sobre la misma opción, se mostraba otra ventana nueva igual a la anterior, es decir, se creaban duplicados o triplicados, lo cual para el proyecto no era lo adecuado. Empezamos a indagar que pasaba con tal caso, cómo podríamos hacer para que no sucediera esto y nuestro profesor muy sabiamente dijo, eso se resuelve con el patrón Singleton.

Empezamos a buscar información sobre este patrón y nos encontramos que la finalidad de este patrón es poder crear una sola instancia de una Clase, por lo tanto si se intentaba crear una nueva instancia se llamaba a la misma creada anteriormente, garantizando así la no duplicación. Ahora bien ahora lo que nos faltaría por ver es como puede llevarse a cabo este patrón:

Existen varias maneras de implementar Singleton, aquí va la más utilizada:



public class ClaseSingleton {

private static ClaseSingleton instancia = null;

private ClaseSingleton() { } //constructor privado

public static ClaseSingleton getInstanciaUnica() {

if (instancia == null) {
instancia = new ClaseSingleton();
}
return instancia;
}
}


Como puede verse existe en la clase un constructor privado, esto se hace con la finalidad de que sólo la clase singleton pueda crear instancias. Existe también un método getInstanciaUnica que crea la instancia si aun no ha sido creada, pero si ya fue creada una, devuelve la misma creada anteriormente.

Veamos un ejemplo con las Ventanas de javax.swing:
Clase Principal: Con Main:


package patronesdisenio;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class VentanaPrincipal extends JFrame
implements ActionListener {

public VentanaPrincipal() {
super("Ventana Principal");
JButton boton = new JButton("Nueva Ventana");
Container contenedor = getContentPane();
contenedor.add(boton, BorderLayout.SOUTH);
boton.addActionListener(this);
setSize(600, 600);
setVisible(true);
}

public static void main(String[] args) {
VentanaPrincipal app = new VentanaPrincipal();
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public void actionPerformed(ActionEvent e) {
VentanaAuxiliar.getVentanaAuxiliarUnica();
}
}


Aquí la Ventana Auxiliar a llamar (Singleton)


package patronesdisenio;

import javax.swing.JDialog;

public class VentanaAuxiliar extends JDialog{

public static VentanaAuxiliar vtnUnica = null;

private VentanaAuxiliar(){ }

public static VentanaAuxiliar
getVentanaAuxiliarUnica(){
if(vtnUnica == null){
vtnUnica = new VentanaAuxiliar();
vtnUnica.setTitle("Ventana Auxiliar");
vtnUnica.setSize(490, 400);
vtnUnica.setVisible(true);
return vtnUnica;
}
return vtnUnica;
}
}


De esta manera cuando se llame a la ventana auxiliar desde la ventana principal con el botón inferior, no se generará ventana duplicada ya que Ventana auxiliar es singleton.