No es un bug, es una característica no documentada

miércoles, 20 de mayo de 2015

Entornos de desarrollo. Modelo - Vista - Controlador (con ejemplo de conversor)

10:19 Posted by Inazio , No comments
El modelo–vista–controlador (MVC) es un patrón de arquitectura de software que separa los datos y la lógica de negocio de una aplicación de la interfaz de usuario y el módulo encargado de gestionar los eventos y las comunicaciones. Para ello MVC propone la construcción de tres componentes distintos que son el modelo, la vista y el controlador, es decir, por un lado define componentes para la representación de la información, y por otro lado para la interacción del usuario. Este patrón de arquitectura de software se basa en las ideas de reutilización de código y la separación de conceptos, características que buscan facilitar la tarea de desarrollo de aplicaciones y su posterior mantenimiento.

De manera genérica, los componentes de MVC se podrían definir como sigue:

  • El Modelo: Es la representación de la información con la cual el sistema opera, por lo tanto gestiona todos los accesos a dicha información, tanto consultas como actualizaciones, implementando también los privilegios de acceso que se hayan descrito en las especificaciones de la aplicación (lógica de negocio). Envía a la 'vista' aquella parte de la información que en cada momento se le solicita para que sea mostrada (típicamente a un usuario). Las peticiones de acceso o manipulación de información llegan al 'modelo' a través del 'controlador'.
  • El Controlador: Responde a eventos (usualmente acciones del usuario) e invoca peticiones al 'modelo' cuando se hace alguna solicitud sobre la información (por ejemplo, editar un documento o un registro en una base de datos). También puede enviar comandos a su 'vista' asociada si se solicita un cambio en la forma en que se presenta el 'modelo' (por ejemplo, desplazamiento o scroll por un documento o por los diferentes registros de una base de datos), por tanto se podría decir que el 'controlador' hace de intermediario entre la 'vista' y el 'modelo'
  • La Vista: Presenta el 'modelo' (información y lógica de negocio) en un formato adecuado para interactuar (usualmente la interfaz de usuario) por tanto requiere de dicho 'modelo' la información que debe representar como salida.
Imagen extraida de http://www.antoniorios.net/blog

Sabiendo esto, vamos a realizar en Java un conversor de divisas (o conversor de monedas, que viene siendo lo mismo) implementando el Modelo - Vista - Controlador.

La aplicación que queremos obtener es la siguiente:


La estructura de las clases y paquetes que necesitaremos será:


Y el código a programar quedaría tal que así:

ARCHIVO CONVERSORDIVISAS.JAVA

package conversorModelo;
import java.util.*;

public class ConversorDivisas {
    
     // Propiedades
     private Hashtable<String, Double> tablaConversion = new Hashtable<String, Double>();// Codigo de divisa e importe en euros
    
     // Constructor
     public ConversorDivisas(){
          insertarDivisa("EUR", 1.0); // Euro
          insertarDivisa("USD", 1.180); // Dolar estadounidense
          insertarDivisa("JPY", 134.86); // Yen japonés
          insertarDivisa("BGN", 1.958); // Lev búlgaro
     }

     private void insertarDivisa(String codigo, Double tipoCambio) {
          tablaConversion.put(codigo, tipoCambio);
     }
    
     private double obtenerDivisa(String codigoDivisa){
          return tablaConversion.get(codigoDivisa);
     }
    
     public Double convertir(String codDivOrigen, String codDivDestino, Double importe){
          Double euros = importe / obtenerDivisa(codDivOrigen); // Primero convierto a euros
          return euros * obtenerDivisa(codDivDestino); // Luego a la unidad de destino
     }
    
     public Enumeration<String> obtenerCodigosDivisa(){
          return tablaConversion.keys();
     }
}

ARCHIVO VENTANAPRINCIPAL.JAVA

package conversorVista;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.util.*;
import conversorControlador.ControladorConversor;

public class VentanaPrincipal extends JFrame {

     private static final long serialVersionUID = 1L;
     // Propiedades
     private JPanel contentPane;
     private JTextField txtImporte;
     private JButton btnConvertir;
     private JComboBox<String> comboDivD;
     private JComboBox<String> comboDivO;
     private JLabel lblResultado;
     private JLabel lblImporte;
     private JLabel lblConvertir;

    
     // Constructor
     public VentanaPrincipal() {
          setTitle("Conversor de divisas");
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          setBounds(100, 100, 309, 237);
          contentPane = new JPanel();
          contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
          setContentPane(contentPane);
          contentPane.setLayout(null);
         
          lblImporte = new JLabel("Introduce importe: ");
          lblImporte.setFont(new Font("MV Boli", Font.BOLD, 12));
          lblImporte.setBounds(10, 11, 131, 14);
          contentPane.add(lblImporte);
         
          lblConvertir = new JLabel("Convertir a:");
          lblConvertir.setFont(new Font("MV Boli", Font.BOLD, 12));
          lblConvertir.setBounds(10, 74, 91, 14);
          contentPane.add(lblConvertir);
         
          lblResultado = new JLabel("Resultado: ");
          lblResultado.setFont(new Font("MV Boli", Font.BOLD, 18));
          lblResultado.setBounds(10, 165, 267, 27);
          contentPane.add(lblResultado);
         
          txtImporte = new JTextField();
          txtImporte.setBounds(10, 36, 131, 20);
          contentPane.add(txtImporte);
          txtImporte.setColumns(10);
         
          btnConvertir = new JButton("Convertir");
          btnConvertir.setFont(new Font("MV Boli", Font.BOLD, 12));
          btnConvertir.setBounds(175, 104, 102, 23);
          contentPane.add(btnConvertir);
         
          comboDivO = new JComboBox<String>();
          comboDivO.setBounds(175, 36, 102, 20);
          contentPane.add(comboDivO);
         
          comboDivD = new JComboBox<String>();
          comboDivD.setBounds(10, 105, 102, 20);
          contentPane.add(comboDivD);
         
          JSeparator separator = new JSeparator();
          separator.setBounds(10, 152, 273, 2);
          contentPane.add(separator);
     }
    
     // Metodos
     public void arrancar() {
          EventQueue.invokeLater(new Runnable() {
                public void run() {
                     try {
                          setVisible(true);
                          setLocationRelativeTo(null);
                     } catch (Exception e) {
                          e.printStackTrace();
                     }
                }
          });
     }
    
     public Double obtenerImporte(){
          try{
                // return Double.valueOf(txtImporte.getText());
                return Double.valueOf(txtImporte.getText());
          }
          catch(NumberFormatException e){
                return 0.0D;
          }
     }
    
     public String obtenerDivisaOrigen(){
          return comboDivO.getSelectedItem().toString();
     }
    
     public String obtenerDivisaDestino(){
          return comboDivD.getSelectedItem().toString();
     }
    
     public void actualizarResultado(String importe){
          lblResultado.setText("Resultado: " + importe + " " + obtenerDivisaDestino());
     }
    
     public void setComboDivisas(Enumeration<String> codigosDivisas){
         
          String elemento;
          while(codigosDivisas.hasMoreElements()){ // Mientras tenga más elementos
                elemento = codigosDivisas.nextElement(); // Almacenar elemento en variable
                // Añadimos elemento a ambos comboBox
                comboDivD.addItem(elemento);
                comboDivO.addItem(elemento);
          }
     }
    
     // El que escucha la acción no es la ventana, es el controlador
     public void conectarControlador(ControladorConversor controlador){
          btnConvertir.addActionListener(controlador);
     }
}

ARCHIVO CONTROLADORCONVERSOR.JAVA

package conversorControlador;
import java.awt.event.*;
import java.text.DecimalFormat;

import conversorVista.VentanaPrincipal;
import conversorModelo.ConversorDivisas;

public class ControladorConversor implements ActionListener{

     // Propiedades
     private VentanaPrincipal ventana;
     private ConversorDivisas modelo;
    
     // Constructor
     public ControladorConversor(VentanaPrincipal v, ConversorDivisas m){
          this.ventana = v;
          this.modelo = m;
         
          ventana.setComboDivisas(modelo.obtenerCodigosDivisa());
     }

     public void actionPerformed(ActionEvent e) {
         
          // Obtengo los valores para operar
          Double importe = ventana.obtenerImporte();
          String codDivisaOrigen = ventana.obtenerDivisaOrigen();
          String codDivisaDestino = ventana.obtenerDivisaDestino();
         
          // Realizo la conversion
          Double resultado = modelo.convertir(codDivisaOrigen, codDivisaDestino, importe);
         
          // Muestro el resultado en la etiqueta Resultado
          DecimalFormat df = new DecimalFormat("#,###.##"); // Formateo salida a dos decimales
          ventana.actualizarResultado(df.format(resultado).toString());
     }
}

ARCHIVO PROGRAMAPRINCIPAL.JAVA

package programaPrincipal;
import conversorControlador.ControladorConversor;
import conversorModelo.ConversorDivisas;
import conversorVista.VentanaPrincipal;

public class ProgramaPrincipal {

     public static void main(String[] args) {
         
          // Propiedades
          ConversorDivisas modelo = new ConversorDivisas();
          VentanaPrincipal vista = new VentanaPrincipal();
          ControladorConversor controlador = new ControladorConversor(vista, modelo);
         
          // Métodos
          vista.conectarControlador(controlador); // Conecto la vista al controlador
          vista.arrancar(); // Muestro la interfaz gráfica
     }

}

El resultado final, ya funcionando, es el siguiente:

0 comentarios:

Publicar un comentario