materials

El patrón Modelo-Vista-Controlador

Modelo-vista-controlador (MVC) es un patrón de arquitectura de software muy utilizado en la actualidad en desarrollo web (y también en muchas aplicaciones de escritorio). Este patrón propone separar la aplicación en componentes distintos: el modelo, la vista y el controlador:

Además de estos componentes usualmente tendremos otros como:

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.

Una aplicación sin MVC

Si una aplicación no utiliza este modelo la función que responde a una acción del usuario debe:

Por ejemplo vamos a hacer una aplicación para gestionar un almacén. Entre otras muchas cosas tendrá una función (podemos llamarle addProduct) que se encargue de añadir un nuevo producto al almacén y dicha función deberá realizar:

// La función que se ejecuta cuando el usuario envía el
// formulario para añadir un producto debería hacer:
document.getElementById('product-form').addEventListener('submit', async (event) => {
    event.preventDefault()
    // Coge los datos del formlario
    const name = document.getElementById('product-form-name').value
    const price = document.getElementById('product-form-name').price
    ...
    // Valida cada dato
    if (!name || name.length < 5 || ...)
    ...
    // Gestiona los posibles errores en la validación

    // Añade el producto a la BBDD
    let newProd = {}
    try {
        const prod = await addProductToDatabase(payload)
        newProd = new Product(prod.id, prod.name, prod.price, prod.units)
        this.products.push(newProd)
    } catch(err) {
        // Gestiona los posibles errores producidos al añadir el producto
        return
    }
    ...
    // Pinta en la página el nuevo producto
    const DOMproduct = document.createElement('tr')
    DOMproduct.innerHTML = `
        <td>${newProd.id}</td>
        <td>${newProd.name}</td>
        <td>${newProd.price}</td>
        <td>${newProd.units}</td>`
    document.getElementById('products-table').apendChild(DOMproduct)
    ...
})

Como vemos, se va a convertir en una función muy grande y que se encarga de muchas cosas distintas por lo que va a ser difícil mantener ese código. Además toda la función es muy dependiente del HTML (en muchas partes se buscan elementos por su id).

Nuestro patrón MVC

En una aplicación muy sencilla podemos no seguir este modelo pero en cuanto la misma se complica un poco es imprescindible programar siguiendo buenas prácticas ya que si no lo hacemos nuestro código se volverá rápidamente muy difícil de mantener.

Hay muchas formas de implementar este modelo. Si estamos haciendo un proyecto con OOP podemos seguir el patrón MVC usando clases. Si sólo usamos programación estructurada será igual pero en vez de clases y métodos tendremos funciones.

Para organizar el código crearemos subcarpetas dentro de la carpeta src:

De este forma, si quiero cambiar la forma en que se muestra algo voy directamente a la vista y modifico la función que se ocupa de ello.

La vista será una clase cuyas propiedades serán elementos de la página HTML a los que accedamos frecuentemente, para no tener que buscarlos cada vez y por si tienen que estar disponibles para el controlador. Contendrá métodos para renderizar los distintos elementos de la vista.

El controlador será una clase cuyas propedades serán el modelo y la vista, de forma que pueda acceder a ambos elementos. Tendrá métodos para las distintas acciones que pueda hacer el usuario (y que se ejecutarán como respuesta a dichas acciones, como veremos en el tema de eventos). Cada uno de esos métodos llamará a métodos del modelo (para obtener o cambiar la información necesaria) y posteriormente de la vista (para reflejar esos cambios en lo que ve el usuario).

Por su parte el modelo gestionará los datos de la aplicación llamando a los servicios para obtener datos del servidor o guardar en él las modificaciones pertinentes.

El fichero principal de la aplicación instanciará un controlador y lo inicializará.

Por ejemplo, siguiendo con la aplicación para gestionar un almacén. El modelo constará de la clase Store que es nuestro almacén de productos (con métodos para añadir o eliminar productos, etc) y la clase Product que gestiona cada producto del almacén (con métodos para crear un nuevo producto, etc).

El fichero principal sería algo como:

const storeApp = new Controller()		// crea el controlador
storeApp.init()				// lo inicializa

// En desarrollo podemos añadir algunas líneas que luego quitaremos para
// imitar acciones del usuario y así ver el funcionamiento de la aplicación:
storeApp.addProductToStore({ name: 'Portátil Acer Travelmate E2100', price: 523.12 })
storeApp.changeProduct({ id: 1, price: 515.95 })
storeApp.deleteProduct(1)

Podéis obtener más información y ver un ejemplo más completo en https://www.natapuntes.es/patron-mvc-en-vanilla-javascript/