El patrón Modelo-Vista-Presentador (MVP) es una arquitectura utilizada para organizar aplicaciones con interfaz gráfica separando la lógica de presentación de la propia interfaz y de los datos de la aplicación. Su objetivo principal es evitar que una única clase termine acumulando la gestión de eventos, la lógica de negocio y la representación visual.
MVP pertenece a la familia de patrones de arquitectura para interfaces de usuario relacionados con MVC y otras variantes de separación entre presentación y lógica. Martin Fowler explica que existen distintas interpretaciones de MVP y que el patrón evolucionó hacia variantes como Supervising Controller y Passive View.
La idea fundamental es sencilla: la Vista muestra información y recibe las acciones del usuario, el Presentador coordina lo que debe suceder y el Modelo representa los datos y la lógica de la aplicación.
¿Qué es el patrón MVP?
MVP son las siglas de Model-View-Presenter, que en español podemos traducir como Modelo-Vista-Presentador.
La arquitectura divide la aplicación en tres elementos:
┌──────────────┐
│ VISTA │
│ Interfaz │
└──────┬───────┘
│
│ acciones
↓
┌──────────────┐
│ PRESENTADOR │
│ Lógica de │
│ presentación │
└──────┬───────┘
│
↓
┌──────────────┐
│ MODELO │
│ Datos y │
│ lógica │
└──────────────┘
La separación permite colocar cada responsabilidad en un lugar concreto. La Vista no debería encargarse de resolver toda la lógica de la aplicación, mientras que el Modelo no debería depender de los elementos visuales.
Esta separación entre presentación y lógica de dominio es uno de los principios fundamentales de las arquitecturas de interfaces.
¿Qué hace el Modelo?
El Modelo representa los datos y las operaciones que necesita la aplicación.
Por ejemplo, imaginemos una aplicación para gestionar usuarios. El Modelo podría encargarse de operaciones como:
obtenerUsuario()
crearUsuario()
actualizarUsuario()
eliminarUsuario()
El Modelo podría comunicarse con una base de datos, una API o cualquier otra fuente de información.
Una posible clase sería:
public class Usuario {
private String nombre;
private String email;
public Usuario(String nombre, String email) {
this.nombre = nombre;
this.email = email;
}
public String getNombre() {
return nombre;
}
public String getEmail() {
return email;
}
}
En una aplicación real, el Modelo puede estar formado por varias clases, repositorios, servicios y otras estructuras.
Lo importante es que no debería contener código específico de la interfaz gráfica.
¿Qué hace la Vista?
La Vista es la parte encargada de mostrar información al usuario y recoger sus acciones.
Puede ser una ventana, una página, una pantalla de una aplicación móvil o cualquier otro componente de interfaz.
Por ejemplo:
Nombre: Antonio
Email: antonio@example.com
[ Guardar ]
Cuando el usuario pulsa el botón Guardar, la Vista comunica esa acción al Presentador.
En una implementación de tipo MVP, la Vista intenta mantenerse sencilla. En algunas variantes, puede limitarse prácticamente a mostrar los datos que recibe del Presentador. En otras, puede encargarse de pequeñas operaciones de presentación.
Martin Fowler distingue precisamente diferentes variantes de MVP según cuánto trabajo de presentación queda en la Vista y cuánto asume el Presentador.
¿Qué hace el Presentador?
El Presentador es el componente que coordina la interacción entre la Vista y el Modelo.
Por ejemplo, cuando el usuario pulsa un botón:
Usuario
↓
Vista
↓
Presentador
↓
Modelo
↓
Presentador
↓
Vista
El Presentador puede recibir la acción, solicitar información al Modelo y decidir qué debe mostrar la Vista.
Por ejemplo:
public class UsuarioPresenter {
private UsuarioView view;
public UsuarioPresenter(UsuarioView view) {
this.view = view;
}
public void cargarUsuario() {
Usuario usuario = obtenerUsuario();
view.mostrarNombre(usuario.getNombre());
view.mostrarEmail(usuario.getEmail());
}
private Usuario obtenerUsuario() {
return new Usuario(
"Antonio",
"antonio@example.com"
);
}
}
La Vista no necesita conocer todos los detalles de cómo se obtiene el usuario.
¿Cómo funciona MVP?
Podemos entender el funcionamiento mediante un ejemplo sencillo.
Imaginemos una pantalla con un botón:
┌─────────────────────────┐
│ │
│ Cargar usuario │
│ │
│ [ CARGAR ] │
│ │
└─────────────────────────┘
El usuario pulsa el botón.
La Vista informa al Presentador:
Vista
│
│ usuarioPulsoCargar()
↓
Presentador
El Presentador solicita los datos:
Presentador
│
│ obtenerUsuario()
↓
Modelo
El Modelo devuelve la información:
Modelo
│
│ Usuario
↓
Presentador
Finalmente, el Presentador indica a la Vista qué debe mostrar:
Presentador
│
│ mostrarUsuario()
↓
Vista
El resultado podría ser:
Nombre: Antonio
Email: antonio@example.com
Implementación sencilla de MVP
Una forma sencilla de implementar MVP consiste en crear una interfaz para la Vista.
Por ejemplo:
public interface UsuarioView {
void mostrarNombre(String nombre);
void mostrarEmail(String email);
void mostrarError(String mensaje);
}
Después podemos crear el Presentador:
public class UsuarioPresenter {
private UsuarioView view;
public UsuarioPresenter(UsuarioView view) {
this.view = view;
}
public void cargarUsuario() {
try {
Usuario usuario = obtenerUsuario();
view.mostrarNombre(usuario.getNombre());
view.mostrarEmail(usuario.getEmail());
} catch (Exception e) {
view.mostrarError(
"No se ha podido cargar el usuario"
);
}
}
private Usuario obtenerUsuario() {
return new Usuario(
"Antonio",
"antonio@example.com"
);
}
}
La implementación concreta de la Vista dependerá del entorno utilizado.
Podría ser una actividad Android, una ventana de escritorio, una página web o cualquier otro tipo de interfaz.
Ejemplo completo
Podemos representar una pequeña aplicación de usuarios mediante tres componentes.
Modelo
public class Usuario {
private String nombre;
public Usuario(String nombre) {
this.nombre = nombre;
}
public String getNombre() {
return nombre;
}
}
Vista
public interface UsuarioView {
void mostrarUsuario(String nombre);
void mostrarError(String mensaje);
}
Presentador
public class UsuarioPresenter {
private UsuarioView view;
public UsuarioPresenter(UsuarioView view) {
this.view = view;
}
public void cargarUsuario() {
Usuario usuario =
new Usuario("Antonio");
view.mostrarUsuario(
usuario.getNombre()
);
}
}
La comunicación quedaría así:
Usuario
│
↓
┌───────────────┐
│ MODELO │
└───────┬───────┘
│
↓
┌───────────────┐
│ PRESENTADOR │
└───────┬───────┘
│
↓
┌───────────────┐
│ VISTA │
└───────────────┘
MVP y separación de responsabilidades
Una de las principales razones para utilizar MVP es mantener separadas las responsabilidades.
Sin una arquitectura de este tipo, podríamos terminar con una clase que haga simultáneamente:
Leer botón
Consultar base de datos
Validar información
Realizar cálculos
Actualizar interfaz
Gestionar errores
Guardar datos
A medida que la aplicación crece, este enfoque puede dificultar el mantenimiento y las pruebas.
Con MVP podemos distribuir esas responsabilidades:
Vista
→ Interfaz y eventos
Presentador
→ Lógica de presentación
Modelo
→ Datos y operaciones
La separación no implica necesariamente que cada aplicación tenga exactamente las mismas clases o relaciones. MVP ha tenido diferentes implementaciones y variantes a lo largo del tiempo.
MVP y las pruebas unitarias
Una de las razones por las que MVP resulta interesante es que permite trasladar buena parte de la lógica de presentación fuera de la interfaz gráfica.
Esto facilita probar el Presentador de forma independiente.
Por ejemplo, podemos crear una Vista simulada:
public class UsuarioViewFake
implements UsuarioView {
public String nombre;
@Override
public void mostrarUsuario(String nombre) {
this.nombre = nombre;
}
@Override
public void mostrarError(String mensaje) {
}
}
Después podemos comprobar el comportamiento del Presentador:
UsuarioViewFake view =
new UsuarioViewFake();
UsuarioPresenter presenter =
new UsuarioPresenter(view);
presenter.cargarUsuario();
Y comprobar que:
view.nombre
contiene el resultado esperado.
La idea de separar la lógica de presentación facilita este tipo de pruebas porque no es necesario ejecutar toda la interfaz para comprobar determinados comportamientos. Fowler señala precisamente la capacidad de probar la lógica sin depender de la interfaz como una de las ventajas de separar la presentación.
MVP frente a MVC
MVP y MVC (Model-View-Controller) comparten muchas ideas, por lo que es habitual confundirlos.
En términos generales:
| MVP | MVC |
|---|---|
| Modelo | Modelo |
| Vista | Vista |
| Presentador | Controlador |
| El Presentador coordina la interacción | El Controlador gestiona determinadas acciones |
| Puede utilizar una Vista pasiva | La relación entre Vista y Controlador depende de la implementación |
Sin embargo, no existe una única implementación universal de MVC ni de MVP. La terminología ha evolucionado y distintos frameworks utilizan estos nombres de maneras diferentes.
Por eso es más útil fijarse en qué responsabilidades tiene realmente cada componente que simplemente en el nombre de la arquitectura.
MVP frente a MVVM
Otra arquitectura relacionada es MVVM (Model-View-ViewModel).
MVVM introduce un ViewModel que representa el estado y comportamiento relacionado con la presentación, normalmente utilizando mecanismos de enlace de datos para sincronizar la interfaz con ese estado. Microsoft, por ejemplo, describe MVVM como una forma de desacoplar el código de interfaz del código que no pertenece a la interfaz.
La diferencia conceptual puede resumirse así:
MVP
Vista
↕
Presentador
↕
Modelo
Mientras que en MVVM:
Vista
↕
ViewModel
↕
Modelo
Aunque los conceptos pueden parecer similares, las responsabilidades concretas dependen de la implementación y del framework utilizado.
Variantes de MVP
No existe una única forma de implementar MVP.
Entre las variantes históricas se encuentra Passive View, donde la Vista es deliberadamente pasiva y el Presentador asume prácticamente toda la lógica de presentación. Fowler también describe Supervising Controller, donde la Vista puede encargarse de parte de la lógica sencilla mientras el Presentador gestiona las interacciones y la lógica más compleja.
Esto explica por qué dos proyectos que utilizan MVP pueden tener estructuras bastante diferentes.
Ventajas del patrón MVP
MVP puede aportar varias ventajas cuando se utiliza en aplicaciones con una interfaz suficientemente compleja.
Separación de responsabilidades
Cada componente tiene una función más concreta, lo que facilita comprender la estructura del programa.
Mayor facilidad para realizar pruebas
La lógica del Presentador puede probarse sin tener que depender completamente de la interfaz gráfica.
Mantenimiento
Separar la lógica de presentación de los elementos visuales puede facilitar los cambios posteriores.
Reutilización
Una misma lógica de presentación puede utilizarse con diferentes implementaciones de una Vista en determinados diseños.
Menos lógica en la interfaz
La Vista puede mantenerse más sencilla al delegar las decisiones de presentación en el Presentador.
Inconvenientes de MVP
MVP también tiene algunos inconvenientes.
El principal es que añade más estructura y más clases al proyecto.
Una aplicación pequeña que solamente tiene una pantalla sencilla podría necesitar muy poco código adicional para funcionar correctamente. Introducir Modelo, Vista, Presentador e interfaces puede ser innecesario si el problema es muy pequeño.
Además, un Presentador puede terminar creciendo demasiado si se le asignan demasiadas responsabilidades.
Por ejemplo:
UsuarioPresenter
├── usuarios
├── pagos
├── pedidos
├── autenticación
├── navegación
├── estadísticas
└── configuración
En ese caso, la separación inicial de responsabilidades empieza a perder sentido.
La separación de presentación también implica cierta maquinaria adicional y puede aumentar la complejidad del proyecto. Fowler señala precisamente este equilibrio entre una mejor separación y el coste de introducir más estructura.
¿Cuándo utilizar MVP?
MVP puede resultar apropiado cuando tenemos una aplicación con una interfaz suficientemente compleja y queremos mantener separada la lógica de presentación.
Puede ser especialmente interesante cuando:
- Hay bastante lógica asociada a las pantallas.
- Se necesitan pruebas unitarias de esa lógica.
- La interfaz cambia con frecuencia.
- Existen diferentes implementaciones de una misma Vista.
- Se quiere evitar que las clases de interfaz crezcan demasiado.
- El proyecto tiene una estructura suficientemente grande como para justificar la separación.
En cambio, para una aplicación muy pequeña, introducir una arquitectura completa puede aportar más complejidad que beneficios.
En resumen
El patrón Modelo-Vista-Presentador (MVP) divide una aplicación en tres responsabilidades principales:
MODELO
Datos y operaciones
VISTA
Interfaz y eventos
PRESENTADOR
Coordina la interacción
La Vista recibe las acciones del usuario y las comunica al Presentador. Este utiliza el Modelo para obtener o modificar información y posteriormente indica a la Vista qué debe mostrar.
El flujo básico es:
Usuario
↓
Vista
↓
Presentador
↓
Modelo
↓
Presentador
↓
Vista
Su principal objetivo es separar la lógica de presentación de la interfaz y del resto de la aplicación. Esta separación puede mejorar la organización y facilitar las pruebas, aunque también introduce más clases y complejidad.
MVP no es una receta única: existen diferentes variantes y formas de distribuir las responsabilidades. Por eso, al implementarlo conviene adaptar la arquitectura al framework utilizado y al tamaño real del proyecto, evitando añadir capas innecesarias.
En definitiva, MVP resulta especialmente útil cuando una interfaz empieza a acumular demasiada lógica y necesitamos una forma clara de separar lo que el usuario ve, lo que ocurre cuando interactúa con la aplicación y los datos que utiliza el programa.
Productos recomendados
Seleccionados de nuestra tienda para este tema
Hasta -75%
Plafón LED de techo rectangular ultrafino de 23 pulgadas…
El precio original era: 263,92 €.65,98 €El precio actual es: 65,98 €.
Ver opciones
-95%
Si eres de jerseys navideños feos, este de El Regreso al…
El precio original era: 226,50 €.11,99 €El precio actual es: 11,99 €.
Añadir al carrito




Leave a comment