jueves, mayo 10, 2012

MVC en Java - Model View Controller - Modelo Vista Controlador

Bueno, un tema complicado para escribir ya que se ha escrito demasiado, sobre algo que a mi parecer no tendría mucha relevancia, bueno sí, pero personalmente prefiero otras estructuras de organización de software. En fin, uno de mis amigos, me ha pedido que explique este Patrón de Diseño. Y que por su fama, y buen marketing  de software ha dado origen a otros patrones como el MVP (Model View Presenter)  y todos los model +view +something, Observer, etc. Además, este tópico, ha dado origen a las discusiones de café más apasionadas sobre los patrones de diseño de software y su utilidad real en el desarrollo actual.
Recuerdo haber leído algunos libros y ver representaciones del MVC, pero todos ellos mostraban en sus clases de la capa vista, una referencia a alguna clase de la capa modelo, o viceversa. Pero… y entonces…. tengo una duda; no era que el MVC era una “¿programación en 3 capas?”, y si hablamos de capas, por que existen referencias cruzadas.  Bueno, después de exhaustivos y apasionales debates sobre si el modelo debía considerarse una capa transversal a toda la arquitectura (y algunos otros argumentos más alocados), descubrimos, que el MVC  no fue igual toda la vida (es más hasta el día de hoy encuentro tantos MVC como arquitectos). Pero no todo es tan relativo, se mantiene algunos principios de responsabilidad de las capas.
Inicialmente y a grande rasgos, podemos decir que existen dos formas de MVC. Y la diferencia básica entre el primero y el segundo, es que en el primero (versión inicial), no se tiene una variable de referencia a alguna clase del “Modelo” en la capa de la vista, como mencione anteriormente.
Realizaré la presentacion en dos post, el primero, será el MVC inicial y el segundo el que tome en cuenta las relaciones entre el modelo, y la vista, y por que evoluciono de esta forma.

MVC + V1

La comunicación de cada capa con la inmediata superior, es lo que llevó a mucha gente a llamar a esto “programación en tres capas”. Como se distingue en las relaciones del diagrama, no existe una comunicación directa entre el modelo, y la vista.  Las referencias a interfaces y no directamente hacia las clases, nos permitirán un crecimiento por agregación (crear una clase y agregarla a nuestro software) y no por modificación. Así por ejemplo si en lugar de instanciar en el controlador un JFrame, instanciaramos un JInternalFrame, solo tendríamos que crear un Internal Frame e implementar la interfaz, sin tener que modificar el controlador mas que para cambiar la referencia.  En esta forma de orgenizar el código, solo se utilizan “objetos del lenguaje” (Map), y no "objetos del modelo" (Persona), y es esta característica, la que le dá la pureza de la separación entre capas.

El codigo fuente Java de esta Ejemplo se puede encontrar aquí!

Algunas consideraciones

Como vemos cada una de las clases tienen una referencia a una interfáz, y no a una clases concreta. También se lo puede hacer con clases abstractas, pero debido a la posibilidad de herencia múltiple de interfaces (Una interfaz puede heredar varias interfaces) e implementación múltiple que tienen las clases (Una clase puede implementar varias interfaces), en Java, nos conviene utilizarlo de esta forma para ganar en flexibilidad para agregar y sacar métodos

  ...
  private IControlable controler; 
  public FrmPersona(IControlable controler) {
    super();
    this.controler = controler;
    initGUI();
   }
  ... 
CtrlPersona.java
  ...
  private IDatable myView;
  private IActualizable myModel;
  ... 
Persona.java
  ...
  private IControlable controlador;
  public Persona(IControlable controlador){
 this.controlador = controlador;
  }
  ...

Vista - "Las pantallitas"1

La vista tiene como responsabilidad mostrar  y tomar datos. Las vistas no conocen nada de enteros, o tipos de dato. Todo para ellas son Strings. Con el desarrollo de las tecnologias web, se pensaba en poner validaciones de formato en esta capa (numerales, etc) para no tener que ir hasta los servidores y disminuir tanto performance como experiencia de usuario, pero con las tecnologias asincronas como ajax, esto pronto dejó de ser nacesario. No realiza ningún tipo de validación de negocio, ya que es el modelo el encargado de realizar dichas validaciones. Cada una de las acciones realizadas es una llamada al controlador para que él sea el encargado de tomar cualquier decisión.
  ...
  @Override
  public void setData(Map data) {
      this.txtNombre.setText(data.get(CtrlPersona.NAME));
      this.txtApellido.setText(data.get(CtrlPersona.SURNAME));
      this.txtEdad.setText(data.get(CtrlPersona.AGE));
  }
  ...
 @Override
 public Map getData() {
   Map data = new HashMap();
   data.put(CtrlPersona.NAME, this.txtNombre.getText());
   data.put(CtrlPersona.SURNAME, this.txtApellido.getText());
   data.put(CtrlPersona.AGE, this.txtEdad.getText());
   return data;
 }
 ...
 @Override
 public void actionPerformed(ActionEvent arg0) {
   if(arg0.getSource() == this.btnCancel){
     controler.cacelAction();
   }
   if(arg0.getSource() == this.btnOK){
     controler.oKAction();
   }
 }
 ...

Controlador - "Eso que entedes vos y nadie más... ponelo si querés...pero no pierdas tiempo.. bla bla...bla... cerveza!"1

En la capa de controlador, podemos encontrar que es donde se instancia las interfaces y modelos que el controlador quiere manejar. Una alternativa a esto ultimo, es que las instancias (Tanto de la vista, como del Modelo) sean pasadas como parametros al constructor del controlador.
Algunas de las responsabilidades de esta capa podrían ser las siguientes:
  • Realizar validaciones de formato
  • Subir y bajar variables de sesión
  • Redireccionar y hacer el forwared de las pantallas  y manejar el ciclo de vida de las Interfaces de usuario o sistemas.
  • Capturar tanto las excepciones de negocio, como de formato.
  • Tomar y poner información en las interfaces
  ...
  {
    myView = new FrmPersona(this);
    myModel = new Persona(this);
  }
  ...
  public void oKAction() {
    Map data = myView.getData();
    try{
        ParameterTool.checkMandatoryFields(data);
        ParameterTool.checkInteger(AGE, data.get(AGE));
        myModel.save(data);
    }catch(MenorDeEdadException e){
        setReturningMessage(e.getMessage());
    }catch(IllegalArgumentException e){
        setReturningMessage(e.getLocalizedMessage());
    }
  }
 ...

Modelo - "El diagramita de clases"1

La capa del modelo, es aquella que representa el negocio de la aplicación. Son aquellas clases con estructura de Java Beans que tanto conocemos. En un MVC la lógica de guardado de la base de datos suele estar en las clases del modelo, por supuesto haciendo llamadas a métodos de alguna librería o un paquete de utilidades para conectarnos con las bases. Es la capa que con las sucesivas iteraciones (y evoluciones a stacks de software) ha ido subdividiéndose, en subcapas, como por ejemplo la de repositorios de objetos.
Una responsabilidad de implementación definida e interesante de destacar es la de chequear las reglas del negocio.

Bueno, existe mucho más que se puede decir de este patrón, ya que como dije al principio, se ha hablado mucho. Pero esto es lo que considero importante para poder aplicarlo, no solo de una forma académica, si no también implementable.  En el próximo post escribiré de la evolución del MVC y esto será en los próximos N días.  (O tal vez  N a la M días).
Mi pasión siempre ha sido no solo hablar teóricamente de algo, porque de eso seguro hay mucha gente que puede hablar más y mejor, pero al final del día… siempre soy solo un programador… y quiero ¡ver pantallitas funcionando!

1) Nota: traducidos a lenguaje "jefe" para la fácil adaptacion a todo tipo de públicos.