domingo, 3 de octubre de 2010

El patrón Modelo-Vista-Presentador (MVP) a examen

Desde hace tiempo llevo enfrentándome con diversos patrones de diseño cuyo objetivo principal es el de separar la interfaz de usuario de la lógica de las aplicaciones. Desde mis años de estudiante universitario con Smalltalk y el patrón Modelo-Vista-Controlador (MVC), hasta MVVM con WPF, pasando por MVP, MP y sus variaciones.

Cada vez que he tenido que me embarcaba a usar uno de estos patrones de diseño me encontraba con la misma curva de aprendizaje. Un concepto bastante sencillo pero que ante ciertos escenarios que encontraba en proyectos reales uno no sabe exactamente qué solución tomar.

En esta entrada quiero centrarme en el patrón de diseño Modelo-Vista-Presentador (MVP), pero yendo más allá de la descripción académica de este patrón y enfocándome en cómo puede ser aplicado en aplicaciones reales.

Como he comentado antes, MVP es otro patrón de diseño que tiene como objetivo separar la interfaz de usuario de la lógica de las aplicaciones.

Básicamente este patrón consiste en 3 componentes:

  • La vista. Compuesta de las ventanas y controles que forman la interfaz de usuario de la aplicación.
  • El modelo. Que es donde se lleva a cabo toda la lógica de negocio.
  • El presentador. Escucha los eventos que se producen en la vista y ejecuta las acciones necesarias a través del modelo. Además puede tener acceso a las vistas a través de las interfaces que la vista debe implementar.

image

El concepto de este patrón es bastante sencillo. Por un lado tengo la vista, que se encarga de mostrar la información al usuario y de interactuar con él para hacer ciertas operaciones. Por otro lado, tenemos el modelo que, ignorante de cómo la información es mostrada al usuario, realiza toda la lógica de las aplicaciones usando las entidades del dominio. Y por último tenemos al presentador que es el que “presenta” a ambos actores sin que haya ningún tipo de dependencia entre ellos.

El propósito del presentador tal y como se ha definido en este patrón no establece de manera clara el grado de control que este puede hacer de la vista.

Dependiendo de este grado de control podemos encontrarnos variaciones en la manera de ver MVP. De hecho, algunas de ellas, dejan de ser MVP para convertirse en MVC, por lo cual debemos tener cuidado.

MVP como Controlador Supervisado

Por un lado, podemos tener un presentador que no gestione la forma en que la información es mostrada en la vista. Es la vista quien define la lógica de cómo la información es formateada y mostrada en la pantalla a partir de los controles que contiene. En este caso, el presentador únicamente los casos más complejos para facilitar el trabajo de la vista. Martin Fowler llama a esta variación Controlador Supervisado.

image

Cuando la vista recibe algún evento de ratón o teclado por parte del usuario, delega el control del evento en el presentador. Este puede realizar ciertas operaciones relacionadas con la vista como el control del estado de los controles y después realizar la llamada a algún comando en el modelo que realice la operación requerida por el usuario. El modelo realiza las operaciones pudiendo realizar cambios en su estado generando el evento correspondiente, el cual es manejado por la vista para actualizar los controles de la pantalla.

Hay que tener en cuenta de que el hecho de que la vista pueda hacer referencia al modelo nos da como resultado un diagrama muy parecido al de MVC. Aunque este enfoque nos permita el uso de técnicas de Data Binding. Con lo cual la cantidad de código que la vista y presentador necesitan, se disminuye.

Este enfoque nos va a permitir el uso de técnicas de Data Binding sobre el modelo. Por tanto, la cantidad de líneas de código fuente en la vista y el presentador disminuyen. Si nos fijamos en el diagrama, este es similar al de MVC por lo que hay que tener mucho cuidado en no caer en un cambio de patrón.

MVP como Vista Pasiva

Por otro lado, podemos hacer que el presentador gestione totalmente cómo la información se muestra en la vista. Es decir, tenemos una vista "tonta", sin ningún tipo de lógica, cuya única función es la de mostrar la información que se le pasa a través de la interfaz de la vista. Martin Fowler llama a esta variación Vista Pasiva.

image

En este caso, cuando un usuario realiza alguna operación sobre la interfaz de usuario, la vista delega los eventos sobre el presentador. Este realizará algún cambio sobre la vista para indicar el cambio de estado y hará las llamadas a los comandos sobre el modelo para llevar a cabo la operación requerida por el usuario. Cuando el modelo provoque cambios en su estado, estos serán recogidos por el presentador (al contrario que en el controlador supervisado, que era la vista quien atendía a estos cambios de estado en el modelo), el cual pedirá al modelo los cambios realizados para luego actualizar la vista acorde a los cambios recibidos.

Ejemplo

Supongamos el siguiente ejemplo: Un programa que para una fecha que le introduzcamos, te diga si es pasado, futuro o la fecha del día actual.

image

Cuando el usuario introduce la fecha y pulsa el botón OK, la vista delega el evento de pulsación de botón sobre el presentador. El presentador toma la fecha introducida del cuadro de texto y valida que el contenido tiene el formato de fecha correcto.

Nota: He obviado la posibilidad de usar un control específico para introducir fechas y así ver en qué lugar se pude hacer la validación de datos.

Si la fecha introducida no fuera correcta, el presentador comunicaría al usuario este hecho a través de la vista.

En caso de que la fecha fuese correcta, el presentador realizaría la operación de comprobar la fecha usando el modelo. Al recibir el resultado de la operación, el presentador mostraría el resultado a través de la vista. Por ejemplo, modificando el texto de la etiqueta con el resultado.

En el siguiente diagrama vemos la secuencia de llamadas realizada para el caso de Vista Pasiva:

image

En caso de usar la variación de Controlador Supervisado, supondría que la vista toma el resultado directamente del modelo y que además, la vista define la lógica de cómo el resultado se muestra en la pantalla. En el caso de que la validación de la fecha fallara, el presentador podría, por ejemplo, enviar una excepción hacia la vista que al capturarla decidiría como se mostraría al usuario.

Actualización: 
He creado en Codeplex un proyecto que hace uso de este patrón. Se trata de un sencillo ejemplo de máquina tragaperras sobre Windows Forms. El enlace al proyecto es este.

21 comentarios:

  1. Simple, pero directo! muy bien explicado! Gracias por el post!

    ResponderEliminar
  2. Está fenomenal, bien explicadito y sencillo.
    Me he metido en codeplex, para descargarme el proyecto y echarle un vistazo (para estas cosas, lo mejor es ver cómo se pone en marcha!) y... no hay versión para descarga...

    please, please....
    Gracias!

    ResponderEliminar
  3. No encuentro el proyecto de ejemplo para descargar en el enlace. Verlo sería buenisimo! gracias!

    ResponderEliminar
  4. Gracias por tu aporte! Me sirvió mucho para entender de forma rápida la idea, especialmente el ejemplo. Saludos!

    ResponderEliminar
  5. Una explicación bastante clara. Creo que el siguiente paso es complementar este sencillo ejemplo en codigo.

    Saludos.

    ResponderEliminar
  6. Hola Anonimo.
    De hecho en la actualización tienes un enlace al ejemplo:
    http://mvpslotmachine.codeplex.com/

    Saludos.

    ResponderEliminar
  7. Hola Oscar:

    Me ha encantado tu tutorial, sobre todo el ejemplo. Es genial para comprender el funcionamiento de MVP. Se que has colgado el código en codeplex.
    Me gustaría saber si vas a colgar el proyecto también para que podamos descargarlo y ver el bosque además de los árboles. ¿Tal vez en VB .NET?

    Muchas gracias por tomarte el tiempo de redactar el tutorial.

    Un saludo

    ResponderEliminar
  8. Genial, muchas gracias :)

    ResponderEliminar
  9. Gracias, me resulta de mucha ayuda para un nuevo proyecto personal que estoy empezando.

    Saludos!

    ResponderEliminar
  10. Gracias, buen aporte, saludos desde República Dominicana

    ResponderEliminar
  11. Hola,
    La traduccion de Supervising Controller, no crees que deberia ser Controlador Supervisor? Lo digo porque el controller es quien supervisa a la vista, nadie supervisa al controller. Me ha parecido confuso traducirlo como Controlador Supervisado.

    Gracias

    ResponderEliminar
  12. Me suena más como Controlador de Supervisión, aunque parezca semántica pura.

    ResponderEliminar
  13. Hola, creo que tienes mal la definicion de modelo. El modelo accede a la lógica de datos no a la de negocio, tal y como dices arriba. De la lógica de negocio se encarga el presentador.

    Un saludo.

    ResponderEliminar
    Respuestas
    1. Totalmente incorrecto Anónimo, el modelo represente la lógica de negocio y el controlador la logica de la aplicación. Ahora no entiendo la diferentecia entre MVC y MVP, el presentador hace exactamente lo mismo el controlador.

      Eliminar
  14. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  15. Hola, tengo una pregunta, en el diseño de la vista aplicando el modelo-vista-controlador se pueden aplicar las hojas de estilo CSS si se esta programando en html?agradecería mucho que aclararan esa duda

    ResponderEliminar
  16. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  17. hola cuando se usa patròn de modelo -vista-controlador, en el diseño de la vista se puede aplicar hojas de estilo css?lo digo porque tengo que hacer una aplicaciòn web y quiero hacerla aplicando MVC.

    ResponderEliminar
  18. Excelente ejemplo!, Explicación y código fuente de primer nivel..Saludos.

    ResponderEliminar