martes, 31 de julio de 2007

Principios de Diseño Orientado a Objetos



Para realizar modelos orientados a objetos no esta de mas conocer algunos principios para poder verificar la fortaleza de los mismos. Ya hay una serie de principios que se recomiendan para un diseño orientado a objetos. Entre estos podemos encontrar los siguientes:


Responsabilidad Única

Cada clase debe ser responsable de realizar solo una actividad del sistema


Clase Abierta y Cerrada

Una clase debe ser abierta a la extensión y cerrada a la modificación


Principio de Substitución de Liskov

Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer las diferencias entre ellas


Principio de Inversión de Dependencia

Los modulos de nivel superior no deben depender sino de las abstracciones. Los detalles deben depender a su vez de las abstracciones, no al contrario


Principio de Segregación de Interfaces

La implementación de las abstracciones (que contradictorio) debe estar en la medida de lo posible en interfaces y no en clases


Principio de Equivalencia de Reuso y Distribución

Solo los componentes que se distribuyen de manera final pueden ser reutilizados, el elemento mas importante es entonces el paquete.


Principio de Cierre Común

Los componentes que comparten funciones entre ellos o que dependen uno del otro deberían ser colocados juntos


Principio de Reuso Común

Si se reutiliza una clase de un paquete entonces se reutilizan todas


Principio de Dependencías Aciclicas

Los paquetes y sus dependencias no deben formar ciclos entre si


Principio de Dependencías Estables

Los paquetes menos estables han de depender de los paquetes mas estables


Principio de Abstracción Estable

Los paquetes deben ser más abstractos mientras mas estables son



Los 5 primeros principios son los que no deberían olvidarse mientras se escriben clases, aunque todos los principios son importantes.

Herramientas para Java

Generalmente el manejo de aplicaciones Java es simplemente considerado plano, sin embargo, los desarrollos Java estan plagados de opciones de trabajo que permiten simplificar el desarrollo, distribución, y mantenimiento de las aplicaciones; existen multiples herramientas que pueden hacer más sencillo el trabajo de Java en entornos de trabajo, vamos a revisar algunas de ellas.
  • Eclipse: Es un IDE que permite desarrollar aplicaciones Java de una manera intuitiva. Es completamente gratuito y puede extenderse de manera casi ilimitada con plugins para realizar diferentes tareas además de las que contiene originalmente. En lo personal me encanta su soporte para integrar muchas de las demás herramientas que aquí se mencionan. Pueden encontrar diversas versiones del IDE, opción personal TFTP y Callipso

  • BlueJ: Cuando no requerimos de todo el poder y las gracias que nos ofrece Eclipse, BlueJ es una buena opción, ofrece poco soporte para herramientas avanzadas, pero nos permite desarrollar aplicaciones sencillas, depurarlas de una manera intuitiva y verlas como dibujos. Cualquier cosa seria no cabe en BlueJ pero es ligero y fácil de usar para cuestiones didacticas

  • Ant: Es una herramienta que permite automatizar muchas de las tareas latosas y repetitivas que se realizan en Java, probablemente no entiendan que hacer con Ant y les parezca una forma fastidiosa de escribir XML pero cuando hablemos de Deploy y estrategías de pruebas automatizadas.

  • JUnit: Es una librería realizada completamente en Java que nos permite automatizar las pruebas y condiciones que deben ejecutarse en cada elemento del programa de manera separada o bien de manera integrada, es una forma de saber que las cosas trabajan antes de ponerlas en producción.

  • HttpUnit: Es algo que pegas con el anterior para probar interfaces Web

  • JavaDoc: Parte de la suite Java del SDK que permite generar documentación parecida a la oficial de la API sobre los elementos de los programas que nosotros desarrollemos
Si bien no es indispensable dominar todas estas tecnologías para utilizar Java te pueden hacer la vida bastante fácil.

Listeners

La plataforma Swing se basa primordialmente para el manejo de eventos en el concepto de escucha o Listener; la teoría general establece que existe un objeto al que llamaremos disparador que realiza alguna acción sobre otro objeto reactivo. El objeto entonces informa a varios Listener de que algo ha ocurrido en el disparador. Entonces cada uno de los listeners puede realizar alguna acción en base al evento que ocurrió.

La metáfora que utilizaremos para comprender el concepto es mas o menos el siguiente: Imagina que tenemos un sistema que mide la temperatura del ambiente, este sistema puede conectarse con multiples sistemas independientes; imaginemos entonces que podemos conectar un aparato que pite cada que la temperatura rebase cierto limite, además podemos conectar otro aparato que actualize la temperatura en un sitio Web cada que esta cambie, y podemos conectar más aparatos que realizen funciones diferentes, siempre y cuando sean capaces de saber cuando la temperatura cambia.

Entre los componentes Swing hay una amplia gama de Listener's que se implementan como Interfaces, si queremos que determinada clase responda a los eventos de un objeto es necesario que este implemente la interface Listener adecuada y que se registre con el objeto que genera los reportes de evento. El ejemplo más sencillo es el de los botones comunes y la interfaz ActionListener.


JButton boton = new JButton("El boton");

//ActionListener es la clase encargada de escuchar eventos de acción
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("Se ha hecho click en el botón");
}
}

boton.addActionListener(al);

//Registramos el nuevo objeto como escucha del botón
JButton boton2 = new JButton("Otro boton");
//Podemos agregar un Listener a varios elementos
boton2.addActionListener(al);
//E igualmente podemos registrar mas de un listener por objeto
boton.addActionListener(otro_listener);

//Borramos el registro de escucha cuando deja de interesarnos
boton.removeActionListener(al);


Algunos elementos pueden llegar a tener multiples interfaces para utilizar Listeners, como el caso de los JFrame's, que permiten recibir WindowListener, FrameListener, PropertyChangeListener, MouseListener, MouseMotionListener entre otros. En la documentación de Java pueden encontrarse bastantes referencias a los listeners que acepta cada uno de los componente Swing.

Existen casos de Listeners que declaran muchos métodos, como el caso del WindowListener que implementa windowClosed, windowClosing, windowIconofied, y otros muchos, estos métodos deben cubrirse completamente en cualquier clase que implemente la interfaz, pero para facilitar las cosas por cada una de estas clases existe una clase Adapter que implementa una funcionalidad vacia en todos estos métodos.


//Usando el adapter nos evitamos escribir todos los métodos
WindowListener wl = new WindowAdapter() {
public void windowClosed(WindowEvent we) {
System.out.println("Se cerro la ventana");
}
}

lunes, 30 de julio de 2007

Look And Feel

Java ofrece funcionalidades para cambiar la forma en la que se muestran las ventanas que conforman un sistema, cada parte del sistema completo puede verse como si se encontrara en otro sistema operativo o bien con un esquema gráfico diferente. Por medio de esta herramienta podemos hacer que los desarrollos Java luzcan visualmente como si se hubieran realizado en un lenguaje común, como VB; o ejecutado desde un sistema operativo cualquiera y verse como un Mac o un Windows.

Para establecer el LookAndFeel de un sistema de ventanas se usa código como el siguiente:


try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} cactch(Exception e) {
//No es posible cambiar el Look and Feel;
}


Los LookAndFeel más comunes en Java son los siguientes:






















Clase LookAndFeel
javax.swing.plaf.metal.MetalLookAndFeel LookAndFeel de Java
com.sun.java.swing.plaf.gtk.GTKLookAndFeel GTK+ (Solaris normal)
com.sun.java.swing.plaf.motif.MotifLookAndFeel Motif (Linux viejitos)
com.sun.java.swing.plaf.windows.WindowsLookAndFeel LookAndFeel normal de Windows (No lo recomiendo)


Pueden encontrarse en Internet varios LookAndFeel que pueden mejorar en gran medida nuestra aplicación de manera muy sencilla.

Una nota final: el LookAndFeel se aplica de manera general a las ventanas existentes y las futuras ventanas, y todas las ventanas que existan hasta que se cambie el LookAndFeel.

viernes, 27 de julio de 2007

Menús

El manejo de los menús en Swing se realiza por medio de las clases JMenu, JMenuBar, JCheckBoxMenuItem, JMenuItem, JRadioMenuItem y JPopupMenu. De la misma forma es necesario iniciar con el manejo de los Actions para poder reutilizar eventos a travez del sistema.

Para crear un menú regular necesitamos un objeto JFrame o JInternalFrame para poner en el el menú. Primeramente agregamos un elemento JMenuBar para poder pegar ahi el menú y dentro de el elementos JMenu, y JMenuItem o una de sus subclases en el interior.


JFrame ventana = new JFrame("Ejemplo de menus");

JMenuBar barra = new JMenuBar();
//Ponemos el menu en Vertical
barra.add(Box.createVerticalGlue());

JMenu archivo = new JMenu("Archivo");
JMenuItem guardar = new JMenuItem("Guardar");
archivo.add(archivo);
archivo.addSeparator();

ventana.setMenuBar(barra);


Bueno, esta es la teoría general de los menús, cada uno de los menús puede personalizarse en base a Actions, los actions son elementos que definen como se realiza un determinado proceso, le asignan un nombre y una imagen, lo que lo hace facilmente reutilizable en otros entornos; en este caso hablamos de un patron conocido como Comand, donde el elemento action define como se realiza una operación y puede ser establecido en multiples elementos sin problemas, por ejemplo un botón, un elémento de menú, un espacio de una barra de herramientas etc.

Para crear Actions generalmente se extiende la clase AbstractAction de una manera mas o menos así:


class SalirAction extends AbstractAtion {
public SalirAction(ImageIcon imagen) {
super("Texto", imagen);
}

public static void actionPerformed(ActionEvent ae) {
System.exit(0);
}
}

Action salir = new SalirAction(imagen);
JButton btnSalir = new JButton(salir);
JMenuItem mnuSalir = new JMenuItem(salir);


Con este modelo tanto el boton como el menu comparten el mismo texto y el mismo funcionamiento, lo que hace más fácil reutilizar esta funcionalidad en el sistema. Pero la reutilización de un Action va un poco mas alla, cuando utilizamos un action este establece más propiedades que puden visualizarse en otro elementos. Esto suele establecerse en el constructor de la clase Action por medio del método putValue(clave, valor).


public SalirAction(ImageIcon imagen) {
super("Texto", imagen);

putValue(SHORT_DESCRIPTION, "Tool Tip Text del control que contenga al action");
putValue(NAME, "Nombre del Action");
//Estableces la acción en respuesta a CTRL + A
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
putValue(LONG_DESCRIPTION_KEY, "Descripción larga");
putValue(LARGE_ICON_KEY, imagenGrande);
putValue(SMALL_ICON, imagenChica);
//Establece el nemonico del action a N
putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
//Se establece el estado seleccionado del action
putValue(SELECTED_KEY, Boolean.TRUE);
}


Dependiendo del tipo de control del que se este hablando podemos reutilizar las funcionalidades de las claves anteriores.

jueves, 26 de julio de 2007

Introducción a Swing

El paquete más comunmente utilizado en Java para crear interfaces gráficas es el paquete Swing, este contiene una serie de controles que se puede utilizar pero Swing ws un poco más que solamente controles:
  • Controles GUI para presentación en pantalla.
  • La interfaz Java2D para dibujo en formularios.
  • Look & Feel's intercambiables.
  • Control de operaciones de transferencia (Copiar, Pegar)
  • Registro de acciones deshacibles.
  • Soporte UNICODE.
  • Accesibilidad.
En posteriores posts vamos arevisar algunos conceptos generales y avanzados de Swing más a detalle, por el momento vamos a considerar los patrones que se utilizan en Swing una y otra vez.

  • Action. Action es una clase que engloba cualquier acción que se pueda realizar en el sistema, lo que debería pasar cuando ocurre un evento. Un elémento Action se comporta de manera completamente independiente de sus contenedores, así que podemos hacer que un mismo Actión se corresponda con muchos controles.
  • Listener. El control de eventos en Java se basa en el concepto de escucha o Listener, un escucha es una clase que implementa determinada interfaz de eventos, cuando un objeto dispara un evento utiliza esta interfaz para comunicar a todos los objetos escuchas de que algo ha ocurrido en el. Utilizando los Listeners podemos crear clases de control de multiples elementos o bien tener más de un controlador de evento para un solo control.
  • Model. Un Model define la manera en la que se van a presentar los datos dentro de un control determinado. La mayoría de las funcionalidades de un Model permiten que los datos sean alterados en la manera que se visualizan sin, necesariamente, modificar los datos mismos.
En terminos generales, si queremos que algún elemento reaccione a las acciones del usuario o del sistema mismo deberíamos usar Listener's; si conocemos que esa misma acción debe ocurrir por otras causas deberiamos agregar un Action. Generalmente la idea de cambiar el comportamiento y la visualización de los datos es una responsabilidad del Model.

Recursos sobre JDBC

Algunos enlaces interesantes sobre JDBC:

  1. Curso de JDBC oficial.
  2. Curso de lo mismo pero en Español.
  3. JDBC en el JavaTutorial.

Acceso y abstracción de datos

El acceso a la base de datos suele ser un poco complicado y repetitivo, para manejar las cuestiones generales de datos podemos utilizar algunos patrones de diseño para generar clases que puedan encargarse de conectarse a las bases de datos y actualizar estas de la manera más abstracta posible, el primer paso para esto es la conexión de datos compartida.

Dado que en Java no existen variables globales, es necesario buscar otra aproximación para compartir la conexión a lo largo de toda la aplicación, el modelo Singleton puede ayudarnos en esto, en este modelo existe una clase de la que solamente puede existir un elemento en un determinado momento. Un singleton sencillo podría verse más o menos de la siguiente forma.


public class ConexionDB {
private static ConexionDB instance = null;
private Map conexiones;

//El acceso privado hace imposible instanciar directamente esta clase
private ConexionDB() {
conexiones = new LinkedHashMap();
}

//Si requerimos una instancia de la clase deberiamos llamar a este metodo
private static ConexionDB getInstance() {
//LazyInstancing. Creamos el objeto hasta que se necesita
if(instance == null)
instance = new ConexionDB();
return instance;
}

public Connection getIConnection(String driver, String uri, String user, String pass) {
try {
//Verificamos si la conexión no existe ya en Cache
if(conexiones.hasKey(uri))
return (Connection) conexiones.get(uri);

Class.forName(driver);
Connection c = DriverManager.getConnection(uri, user, pass);
conexiones.put(uri, c);

return c;
} catch(Exception e) {
return null;
}
}

//Simplificamos las llamadas para no depender del Singleton en código general
public static Connection getConnection(String driver, String uri, String u, Stirng p) {
return ConexionDB.getInstance().getIConnection(driver, uri, u, p);
}

//Generalmente siempre se usa una sola conexión a DB por default
public static Connection getDefaultConnection() {
return ConexionDB.getInstance().getIConnection("sun.jdbc.odbc.JdbcOdbcDriver",
"jdbc:odbc:osos", "sa", "admin");
}
}


Para utilizar la conexión en otra clase solamente utilizariamos código sencillo:


Connection c = ConexionDB.getConnection("driver", "uri", "user", "pass");
Connection c2 = ConexionDB.getDefaultConnection();

domingo, 22 de julio de 2007

JDBC Parte 2

Quedamos entonces por empezar con el manejo de consultas con parametros. Normalmente para esto y en la práctica no se utiliza la clase Statement sino la clase PreparedStatement. Vamos a ver como funciona para cosas simples.


PreparedStatement ps = c.prepareStatement("SELECT * FROM tabla");
ResultSet rs = ps.executeQuery();
//Podemos usar ps.executeUpdate();
//para DDL o SQL de actualización y este devuelve un entero con lo que paso


Lo divertido de un PS no es realmente esto, sino las consultas parametrizadas.


try {
PreparedStatement ps = c.prepareStatement("SELECT * FROM tabla WHERE id=?");
ps.setInt(1, 9);
//Igualmente puede utilizarse setString, etc
ResultSet rs = ps.executeQuery();
} catch(Exception e) {
System.out.println("Error en la consulta");
}


Las consultas parametrizadas deberían utilizarse siempre que se actualizan datos a una base de datos para evitar SQLInjection y otros problemas como carácteres extraños y cosas por el estilo.

La clase CallableStatement nos permite tener acceso a procedimientos almacenados en la base de datos que se hayan definido anteriormente. Por ejemplo:


try {
CallableStatement cs = c.prepareCall("{call getDailyTotal (?, ?)}");
cs.setInt(1, 7);
cs.getString(2, "Hola");
} catch(Exception e) {
System.out.println("Error de DB");
}


Sin mayores detalles así funciona. Vamos ahora a terminar con JDBC hablando de las transacciones. Estas se utilizan para crear acciones atómicas sobre la base de datos.


try {
c.setAutoCommit(false);
c.prepareStatement("SQL 1").executeUpdate();
c.prepareStatement("SQL 2").executeUpdate();
c.prepareStatement("SQL 3").executeUpdate();

c.commit();
} catch(Exception e) {
try {
c.rollback();
} catch (Exception exc) { ; }
System.out.println("Error de DB");
}

sábado, 21 de julio de 2007

Conexiones JDBC

La tecnología parte de Java que se encarga de realizar conexiones a bases de datos se conoce como JDBC (Java Data Base Conection); es un estandar que define las reglas que deben seguir cada uno de los proveedores para poder hacer que sus datos sean accesibles en programas Java.

La idea detras de esto es que un constructor de DB crea un programa de base de datos, y una vez creado este se crea entonces una aplicación java conocida como Driver que se encarga de dar los datos a Java de una manera previamente definida.

Los Dirvers de base de datos vienen en varios estilos pero todos funcionan de manera similar en su superficie.

Para establecer una conexión a BD desde Java se necesita:

  1. La clase Driver que se encargara de gestionar la conexión.
  2. Una URL especial para acceder a la base de datos.
  3. Un consumidor de datos (el programa Java mismo).
El código general para establecer una conexión se muestra a continuación, el ejemplo considera un servidor SQL Server con una base de datos llamada osos accesible a traves de un ODBC con la misma dirección.


try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException) {
System.out.println("El Driver no existe");
}

Connection c = null;
try {
// c = DriverManager.getConnection("jdbc:odbc:osos", "usuario", "password");
// en caso de que el ODBC no incluya estos datos.
c = DriverManager.getConnection("jdbc:odbc:osos");
} catch (Exception e) {
System.out.println("No se puede establecer una conexión");
}


La forma de crear la URL que se pasa a getConnection y la clase que se pasa a forName dependen del tipo de base de datos al que se desee conectar, en general usar ODBC es una buena idea, pero la clase que utiliza Java para gestionar el ODBC es muy poco practica, por lo que deberia sustituirse por un Driver especifico. Puede encontrarse en la página de Java una lista de drivers existentes.

Una vez que se dispone del código que genero el objeto Connection se empieza a interactuar con el de una manera común. Se puede utilizar un objeto de esta naturaleza por medio de sentencias o directamente y con o sin transcciones. Primero vamos a revisar como realizar una consulta a la base de datos para obtener datos. Para esto vamos a utilizar la clase Statement, esta clase almacena la mayoría de la funcionalidad de interacción con SQL.


Statement st = c.createStatement();

try {
st.execute("CREATE TABLE");
st.execute("DELETE FROM tabla WHERE id=" + id);
st.execute("INSERT INTO tabla VALUES('id')");
st.execute("ANY_VALID_SQL_FOR_DB");
} catch(Exception e) {
System.out.println("El SQL charcho");
}


Con esta estrategia puedes ejecutar casi todo el SQL que no regrese datos. Ahora, con datos: se necesita ahora la clase ResultSet, que representa un conjunto de datos que se encuentran almacenados en la base de datos. Vamos entonces a lo nuestro.


try {
ResultSet rs = st.executeQuery("SELECT * FROM M");
//mira, primero hay que moverlo
rs.first();
//podemos usar rs.next(), el resto (rs.previous() y rs.last() causan a veces conflictos)

String s = rs.getString("nombre_campo");
String s2 = rs.getString(1); //El primer campo
int pos_campo = rs.findColumn("campo"); //Devuelve la posicion del campo

int r = rs.getInt(2); //Igual existen getDouble(), getLong(), getObject(), entre otros
} catch(Exception e) {
System.out.println("El SQL charcho");
}


Weno, después completo el tema del SQL, quedan pendientes los procedimientos almacenados, la manera realmente practica de hacer las cosas, porque esta es algo viejita y las transacciones. Empiezen a jugar con esto, como ejercicio creen una aplicación Java que cree toda la estructura de una base de datos de una bilbioteca y le inserte algunos datos.

jueves, 19 de julio de 2007

sábado, 14 de julio de 2007

Primeros pininos en Java

Para comenzar a trabajar en java es necesario primero descargar e instalar la versión más reciente del JSDK, para esto puedes visitar la página oficial de Java, al momento de escribir esto la ultima versión del SDK era la 1.6 Update 2.

Para cuestiones generales en lo personal prefiero utilizar un IDE para desarrollo porque hacer las cosas por las malas me da mucha hueva, pero por referencía les dejo los pasos para trabajar el Java desde el principio.

  1. Instalen el SDK de Java.
  2. Abran el Bloc de Notas y escribanle algo de código (ver al final)
  3. Guarden el archivo con el nombre Hello.java
  4. Clic en el botón Inicio, Ejecutar, cmd
  5. En la línea de comandos cambiarse al directorio C:\Archivos de Programa\java\jdk1.6_x_x\bin. (El X_X deberia corresponder con la versión y no me acuerdo bien del nombre pero es algo por el estilo)
  6. En la línea de comandos escribanle javac Hello.java. Debería aparecer un mensaje indicando que no hay problemas, si los hay, hay que corregirlos y volver a empezar.
  7. Una vez que el comando javac no arroje errores ejecute java Hello.


public class Hello {
public static void main(String[] args) {
System.out.println("Mensaje del primer programa");
}
}


Ese es el camino feliz. Dado que no se va a usar esto pues lo dejo así como una referencía y vamos a lo que sigue.

viernes, 13 de julio de 2007

Entrandole al Java

Java es un poderoso lenguaje de programación orientado a objetos desarrollado y distribuido por la empresa Sun Mycrosistems (no se si lo escribi bien). Este lenguaje estaba originalmente pensado para ser utilizado en distintos tipos de dispositivos, como cafeteras, automoviles, etc. La idea general era la de crear un lenguaje de programación que pudiera usarse independientemente del dispositivo.

Si bien Java nunca llegó a este nivel si se constituyo en un lenguaje de facto para Internet, y poco a poco ha venido a ganarse un lugar bastante reconocido en el desarrollo de aplicaciones profesionales. Java es un lenguaje que puede ser utilizado en una gran gama de aplicaciones, desde aplicaciones para celulares, aplicaciones de escritorio, aplicaciones para Internet y para dispositivos específicos; por eso deberiamos empezar por delimitar las "familias" de Java en base a su aplicación en las empresas.

  • Java SE. Es el conjunto básico y original de Java, que permite el desarrollo de aplicaciones de escritorio y de applets. Es la versión más común de Java y suele ser simplemente llamada Java.
  • Java ME. Es una extensión del SE para crear aplicaciones para dispositivos moviles, en realidad el Java ME es un subconjunto de Java SE, pues cuenta con caracteristicas limitadas que permiten que se ejecute en dispositivos con recursos limitados.
  • Java EE. La versión Enterprise de Java esta dedicado a la construcción de aplicaciones empresariales de alto rendimiento. La versión más extensa de Java y una de las mas utilizadas en entornos de aplicaciones empresariales.
El contenido de este blog se enfoca a la versión Java SE, si desea más información sobre el resto de las tecnologías visite la página oficial de Sun java.sun.com.

Hablando un poco más de la implementación de Java este se considera un lenguaje interpretado, esto significa que las aplicaciones no se ejecutan directamente sobre el hardware de la computadora, sino sobre una versión de software sobre este, a este software se le conoce como máquina virtual. Para poder ejecutar una aplicación en Java se necesita solamente la maquina virtual o Runtime Environment, a este se le denomina regularmente Java RE. Si se desea desarrollar una aplicación en Java es necesario una aplicación denominada JSDK (Java Software Development Kit), este es un buen momento para comenzar por descargar el SDK desde la página oficial de Sun... por cierto, el SDK incluye un RE.