viernes, 30 de diciembre de 2011

Patron de diseño: MVC en Java


El tema principal es, aprender a usar uno de los tantos patrones de diseño que existen para el desarrollo de software pero, en Java. Primero veamos un poco de teoría para ir entendiendo de que va esto.

MVC 
MVC viene de las siglas Modelo Vista Controlador. Es un patrón de diseño de software. Aquí se nos presenta el termino "patrón".
Demos una definición simple:  
Un patrón es la abstracción de una forma concreta que puede repetirse en contextos específicos.
Simple, ¿Verdad? Expliquemos lo en cristiano...
 En el desarrollo de software un patron es una forma, un metodo, una manera, un procedimiento. ¿De que? Pues de realizar las cosas, de llevar a cabo el objetivo, de finalizarlo pero, todo esto segun las caracteristicas de los objetivos de la aplicacion, de alli lo de contexto. Y todo el proceso puede repetirse, por eso el termino "patron".

¿Para que?
Cuando desarrollamos software empezamos a escribir código tal cual como las patadas del ahogado. Osea solo nos importa que el problema (el objetivo del programa) se resuelva. Después, cuando tenemos que hacer otro programa iniciamos desde cero y lo normal es que se repita lo de las patadas de ahogado. Incluso, en nuevos programas es posible que tengamos que escribir código que en aplicaciones anteriores ya habíamos realizado.

Aqui es donde intervienen los patrones de diseño. Un patron de diseño nos ayuda a realizar nuestras aplicaciones de manera que se nos faciliten cosas como: 
  • Facilitan  la comunicacion interna
  • Ahorran tiempo y experimentos inutiles
  • Mejoran la calidad del diseño y la implementacion
Ademas de que actuan como "normas" o "buenas practicas de programacion".
Existen varios tipos de patrones, en este caso hablaremos sobre el patron de diseño MVC.

Como habia mencionado antes MVC es Modelo, Vista y Controlador.
Este patron de diseño nos dice que debemos separar nuestro programa en tres partes. Las cuales son las anteriores y nos indican lo siguiente.

Modelo: Es la parte logica del programa, el que resuelve el problema, el que da el resultado. Aqui van los algoritmos y la parte logica, la crucial.
Controlador: Es la seccion que se comunica con el modelo y la vista, obtiene los datos ingresados por el usuario a traves de la vista y lo manda al modelo para que este realice las operaciones correspondientes.
Vista: Esta parte es la que interactua con el usuario y envia los datos al controlador para que se realice la comunicacion con el modelo.

Podriamos decir que el modelo es la parte donde mas vamos a tardar pues es donde debemos resolver el problema. El controlador va muy ligado a la vista y estas dos partes son lo mas facil de realizar, relativamente.

Ahora que ya sabemos que debe hacer cada parte pongamos un ejemplo de algun programa que nos hayan pedido. Digamos que nos encargan realizar un programa que convierta una cantidad a pesos(MXN) y a Dolares(USD).

Realizamos un analisis del problema y ya sabemos como obtener el resultado.
Sabemos que un dolar vale 13,943 pesos y que un peso vale 0.072 dolares.
Entonces las operaciones para realizar la conversion serian: 
moneda * cantidad

Entonces ya tenemos como resolver el problema principal, ahora podemos empezar a escribir codigo.
Lo primero es el modelo. Crearemos un paquete que se llame mvc. En el que iran tres clases.
Modelo.java, Vista.java y Controlador.java.

Coloquemos el codigo de el Modelo:
package mvc;

public class Modelo {
 
 private Double moneda;
 private Double cantidad;
 private Double resultado;
 
 public void setMoneda(Double moneda) {
  this.moneda = moneda;
 }
 public void setCantidad(Double cantidad) {
  this.cantidad = cantidad; 
 }
 public Double getResultado() {
  return resultado;
 }
 public void convetirDolarAPeso() {
  resultado = cantidad * moneda;
 }
 public void convertirPesoADolar() {
  resultado = cantidad * moneda;
 }
}
Explicacion: 
La clase Modelo establece tres variables de clase o globales(atributos) y cinco metodos. Las variables son accedidas y modificadas por los metodos. Usamos los metodos set y get para modificar el valor de las variables cantidad y moneda. Y usamos los metodos que se encargan de realizar la conversion para obtener el resultado.

Ahora veamos el codigo de la Vista:
package mvc;

import java.awt.BorderLayout;
import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Vista extends JFrame{
 public JButton pesos, dolares;
 private JPanel panelB, panelR;
 public JLabel lResultado;
 public JTextField campoTexto;
 
 public Vista() {
  getContentPane().setLayout(new BorderLayout());
  
  panelB = new JPanel();
  panelB.setLayout(new FlowLayout());
  
  panelR = new JPanel();
  panelR.setLayout(new FlowLayout());
  
  pesos = new JButton("Convertir a Pesos");
  dolares = new JButton("Convertir a Dolares");
  
  lResultado = new JLabel("Resultado:");  
  campoTexto = new JTextField(20);
  
  panelB.add(pesos);
  panelB.add(dolares);
  
  panelR.add(lResultado);
  
  add(campoTexto, BorderLayout.NORTH);
  add(panelB, BorderLayout.SOUTH);
  add(panelR, BorderLayout.CENTER);
 }
}
Explicacion:
La clase vista se encarga de crear los componentes Swing que haran la GUI y no explico mas de UI porque eso es tema aparte =P
Basta con saber que hereda el componente JFrame, que contiene dos paneles, dos botones, un label y un textfield.

La clase Controlador:
package mvc;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

public class Controlador implements ActionListener {
 private Modelo modelo;
 private Vista vista;
 private Double cantidad;
 
 public Controlador(Modelo modelo, Vista vista) {
  this.modelo = modelo;
  this.vista = vista;
  
  this.vista.pesos.addActionListener(this);
  this.vista.dolares.addActionListener(this);
 }
 public void iniciarVista() {
  vista.setTitle("Conversor");
  vista.pack();
  vista.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  vista.setLocationRelativeTo(null);
  vista.setVisible(true);  
 }
 public void actionPerformed(ActionEvent evento) {
  if(vista.pesos == evento.getSource()) {
   if(!"".equals(vista.campoTexto.getText())) {
    try{
     cantidad = Double.parseDouble(vista.campoTexto.getText());
     modelo.setCantidad(cantidad);
     modelo.setMoneda(13.943);
     modelo.convetirDolarAPeso();
     vista.lResultado.setText(modelo.getResultado().toString());
    }catch(NumberFormatException e) {
     vista.lResultado.setText("Introduzca una cantidad valida...");
    }
   }
  }
  else if(vista.dolares == evento.getSource()) {
   if(!"".equals(vista.campoTexto.getText())) {
    try{
     cantidad = Double.parseDouble(vista.campoTexto.getText());
     modelo.setCantidad(cantidad);
     modelo.setMoneda(0.072);
     modelo.convertirPesoADolar();
     vista.lResultado.setText(modelo.getResultado().toString());
    }catch(NumberFormatException e) {
     vista.lResultado.setText("Introduzca una cantidad valida...");
    }
   }
  }
 }
}
Explicacion:
La clase Controlador se divide en tres partes importantes, la primera es la declaracion de los atributos de clase y el constructor de la clase. Esta parte crea atributos tipo Modelo y tipo Vista para poder controlar la aplicacion completamente. Ademas le agrega los escuchadores a los botones.

La segunda parte es el metodo iniciarVista(), el cual utilizando la variable vista accede a los componentes Swing correspondientes y realiza las configuraciones para mostrar la ventana(aplicacion).

La tercera parte tiene que ver con los componentes visuales, en este caso los botones que son los que nos dan las ordenes de accion, como la clase implementa la interface ActionListener sobreescribimos el metodo actionPerformed y comprobamos que boton fue clickeado.

Cuando se trata de el boton pesos, sabemos que la cantidad que se encuentra en el campo de texto deben de ser dolares, por lo tanto el valor de la moneda seran 13.943 pesos. Realizamos un parser y usamos el objeto modelo para llamar a los metodos get y set del mismo. Despues realizamos la conversion y establecemos en el label el resultado.

Cuando se trata de el boton dolares el procedimiento es el mismo, solo que esta ves la cantidad se supone esta en pesos, y un peso tiene un valor de 0.072 dolares.

Por ultimo creamos una clase en cualquier paquete que queramos y esta ejecutara nuestra aplicacion.
Por ejemplo:
package ejecutarConversor;

import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import mvc.Controlador;
import mvc.Modelo;
import mvc.Vista;

public class PruebaConversor {
 public static void main(String arf[]) {
  try {
   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
  } 
  catch (UnsupportedLookAndFeelException e) {
  }
  catch (ClassNotFoundException e) {
  }
  catch (InstantiationException e) {
  }
  catch (IllegalAccessException e) {
  } 
  Modelo modelo = new Modelo();
  Vista vista = new Vista();
  Controlador controlador = new Controlador(modelo, vista);
  controlador.iniciarVista();
 }
}

Esta clase crea tres objetos que son, del tipo Modelo, del tipo Vista y del tipo Controlador. A este ultimo le pasamos como parametro los otros dos. Por ultimo, por medio del objeto controlador mandamos mostrar la ventana. El bloque try-catch es solo para la skin o look and feel de la aplicacion.

Por ultimo unas screens de la ejecucion.





















Aqui termina la entrada de el patron de diseño MVC, espero que les sirva y que le hayan entendido.

11 comentarios:

  1. La verdad es una mala implementacion del MVC, ya que los controladores se añaden en la vista no en el controlador, y es la vista quien debe iniciar la vista no el controlador, asi que el main, solo se debe llama a la vista.

    Ademas faltan muchos metodos get y set que permiten la comunicacion entre capas, lo que haria de este modelo más complicado de mantener que si se iniciera sin el MVC

    ResponderEliminar
  2. Lo que me dices es totalmente diferente de lo que he leido. Se que en un principio los investigadores descubrieron tres formas diferentes de implementar el patron MVC.

    La que yo elegi fue una de ellas. Pero bien es cierto que hay errores. Lo que mencionas sobre la comuniciacion entre capas me parece que es genial.
    Que bien que me haces notar este tipo de cosas para aprender bien y mas.
    Gracias por comentar.

    ResponderEliminar
  3. Me parece buen ejemplo. Pero es verdad, creo falla en algunas cosas.

    Por ejemplo, puedes usar interfaces para evitar duplicar el código (convertirPesoADolar y convertirDolarAPeso tienen el mismo código).

    En general es un buen aporte. Puede mejorar. :D

    ResponderEliminar
  4. Hola buen día, pues para ser una aplicación dekstop no esta mal, el modelo en sí se compone básicamente de 3 cosas, las clases entidad (reglas de negocio), las clases que aplican ese negocio y el DAO, modelo mas bien es un paquete y Moneda pudo haber sido tu entidad, todos los atributos del modelo deben llevar setters y getters, sin excepción.

    Implementas dos veces el mismo código en tu modelo, puedes poner solo un método que se llame convertir, una interfaz en este caso no la creo necesaria, porque las interfaces marcan la estructura del negocio con múltiples entidades, pero solo tienes una entidad así que no hay pierde, y bueno ya te mencionaron que los componentes de la vista se inician en la vista, no en el controlador, en tu main solo necesitas llamar a la vista y bueno creo que es todo, si me equivoco o tienen dudas, tengan la confianza de decirlo, saludos.

    ResponderEliminar
  5. Jajaja esto es una copia adaptada de un ejemplo de la Universidad de Madrid...

    Copión di su procedencia hombre!!!

    Pero esta bien

    ResponderEliminar
    Respuestas
    1. ¿Si es algo adaptado sigue siendo una copia? Al cambiar el ejemplo cambio el programa. Ademas no lo hice para hacérmela de muy salsa. Lo he hecho para aprender.

      En todo caso, ¿Esta mal usar material ajeno para aprender? ¿Puedes aprender sin ejemplos? ¿Nunca has adaptado material para tus propios programas? ¿Entonces como aprendiste a programar? Mas bien, ¿Como es que sabes programar? Los códigos con los que iniciaste no los inventaste tu. Fue algo ya inventado. Eso si lo copiaste. Y ¿Cual es el problema? Ninguno. Esa es una de las formas de aprender. No es algo que deba darte gracia. Y menos para mofarse de alguien que lo haga.

      Para promover la retro alimentación te dejo un link de el diccionario de la lengua española para que veas la definición de copiar: http://goo.gl/9HxgE
      Saludos.

      Eliminar
  6. Lo que le falta a esto es ser un MVC de verdad... jejeje... pues lo primero que debe tener es alguna clase de independencia entre capas. Esto se consigue declarando unas interfaces que son accesibles desde la controladora, de tal modo que dicha controladora nunca tiene acceso a la vista en si misma, sino que realiza llamadas a los métodos declarados en dicha interface. por supuesto, creo que no hace falta decir que la vista es la que implementa dichos métodos, de tal modo que cualquier vista que implemente la suso dicha interface será factible de poner en nuestro programa. A eso es a lo que se llama independencia entre capas. Sin embargo lo que has creado aquí tiene un nivel de acoplamiento total. un saludo.

    ResponderEliminar
  7. pues a mí me marcaron una tarea sobre patrones de diseño, estoy aprendiendo java y pues quiero aplicar el mvc...porque en php ya lo hice, aunque con ayuda y aun no lo aprendo bien. Toda esta información me va a servir de mucho, aunque no este super mega bien, pero como dices Kalt Wulx así se aprende cuando copias y lo ADAPTAS no solo copias, pues yo así lo hago, me baso de ejemplos y los adapto a mi forma de programar, y así voy aprendiendo...veamos como me queda mi tarea jejeje...es buen ejemplo, no lo entendí al 100% pero leyendo e investigando más lo entenderé :)

    ResponderEliminar
  8. La idea está bien, pero la implementación no. Aquí te detallo las deficiencias.

    Imagina que el día de mañana quiero cambiar la vista, que ya no sea un JFrame si no un JPanel que estará empotrado en otro JFrame, ahí tu implementación se va al carajo. La vista podría perfectamente ser una interfaz.

    El tu caso, Quien podría modificar tu modelo? Solo se puede modificar mediante la vista, pero si modelo tuviera una una mayor independencia y este cambiase en el transcurso del ciclo de la app, necesitas una manera de notificar a la vista de los cambios, entonces, el modelo debería proveer un mecanismo de registro de evento para notificar cambios al exterior.

    Te felicito por compartir tu trabajo, así ves puntos de vistas y vas mejorando.
    Saludos.

    ResponderEliminar
  9. com puedo enpesar desde cero chavo algo mas simple

    ResponderEliminar

Piensa dos veces o mas antes de escribir... :D