Cómo Implementar el Patrón de Diseño Modelo-Vista-Controlador con Python

El patrón de diseño (Design Pattern) Modelo-Vista-Controlador (MVC) más que un patrón de diseño, puede ser considerado un patrón de arquitectura de software. La diferencia entre el primero y el segundo que que el segundo tiene un alcance mucho mayor, pues define la arquitectura fundamental de la aplicación o sistema que estemos desarrollando. En esta entrada estaremos hablando sobre cómo podemos implementar el MVC en Python.

En el MVC, el Modelo es el componente central y representa el conocimiento. El Modelo contiene y gestiona la lógica del negocio, los datos, el estado y demás reglas fundamentales de la aplicación. Los datos pueden ser almacenados en el propio Modelo o en un base de datos, en este último caso solo el Modelo puede tener acceso a esta base de datos.

La Vista es el componente visual, es decir, una representación visual del Modelo que el usuario generalmente puede ver en pantalla, como por ejemplo: las Interfaces Gráficas de Usuario (GUI por sus siglas en Inglés), o las salidas de texto en una consola o terminal, los gráficos de barras o de pastel, los documentos, las hojas de cálculo, etc. La vista se limita a mostrar al usuario los datos contenidos en el Modelo, sin tener la capacidad de manipularlos o modificarlos. La Vista no debe nunca llamar a sus propios métodos, solo el Controlador debe hacerlo.

El tercer componente de este patrón de diseño es el Controlador, que no es más que el enlace o medio de comunicación entre el Modelo y la Vista. Todo el flujo de comunicación entre el Modelo y la Vista es gestionado a través del Controlador, por tanto, no existirá comunicación directa entre estos. El Controlador acepta las acciones y entradas del usuario y delega la representación de los datos a la Vista y la manipulación al Modelo.

El MVC no es más que la aplicación del principio de “Separación de Responsabilidades” (Separation of Concern) al diseño de aplicaciones, donde cada uno de los componentes del patrón tiene una responsabilidad bien definida y única.

Cómo Funciona MVC en la Práctica

La lógica de funcionamiento del MVC es bastante sencilla. Supongamos que tenemos una aplicación con una GUI donde el usuario puede realizar acciones (hacer click, presionar teclas, tocar el display táctil, etc.). Estas acciones comúnmente se denominan “eventos” y guían el funcionamiento general de la aplicación, pero, qué sucede internamente? Veamos:

  • El usuario ejecuta una acción (evento) sobre la Vista

  • La Vista recibe la acción e inmediatamente informa o notifica al Controlador sobre la acción del usuario

  • El Controlador a su vez, procesa la acción del usuario e interactúa con el Modelo realizando la petición prevista para responder a la acción ejecutada por el usuario

  • El Modelo realiza toda la validación de los datos y las entradas del usuario y luego procesa los requerimientos y realiza los cambios de estado solicitados, para finalmente informar al Controlador que el cambio de estado correspondiente ha sido ejecutado

  • El Controlador recibe la información (de cambio de estado) generada por el Modelo y se la envía a la Vista, quien se encargará de mostrarla en pantalla.

Haciendo una analogía podemos comparar el MVC con un restaurante, donde la carta sería la Vista, el mesero sería el Controlador que recibe la orden del cliente y se la transmite al chef, que representaría al Modelo y que es el encargado de confeccionar el plato solicitado por el cliente. Una vez que el plato está listo, el chef se lo hace saber al mesero, quien finalmente sirve la comida al cliente. Como se puede apreciar en este ejemplo, el chef y el cliente no tienen contacto directo, lo que constituye un principio básico de este patrón de diseño.

Ventajas del MVC

Si empleamos coherentemente el patrón de diseño MVC en el desarrollo de nuestros proyectos de software, obtendremos las ventajas siguiente:

  • La separación entre la Vista y el Modelo permite que los diseñadores gráficos puedan dedicarse al diseño de la interfaz (GUI por sus siglas en Inglés) a la vez que los programadores se encargan de programar y probar el Modelo, sin ninguna interferencia entre ellos. Luego solo sería necesario programar el Controlador adecuado y la aplicación quedaría lista

  • Debido a la poca o nula interdependencia entre el Modelo y la Vista, cada parte puede ser modificada de manera independiente sin que se afecte la otra

  • El proceso de añadir nuevas Vistas es trivial, solo se necesita implementar el Controlador adecuado y listo

  • Como el Modelo no tiene conocimiento de las Vistas, es posible tener varias Vistas diferentes para un único Modelo

  • Mantener cada parte es mucho más fácil, debido a que las responsabilidades están claramente definidas

  • MVC incrementa la flexibilidad y fomenta la reutilización del código.

Asignación de Responsabilidades en el MVC

Para implementar el patrón MVC desde cero, debemos asegurarnos de crear Modelos inteligentes que recojan todo el conocimiento y la lógica del negocio; Controladores delgados que se limiten a canalizar el flujo de información de la Vista al Modelo y viceversa; y Vistas que se limiten mostrar la información de estado del Modelo.

Para que el Modelo pueda ser considerado “inteligente” debe:

  • Contener todas las reglas de validación de entradas y la lógica del negocio

  • Manipular el estado de la aplicación

  • Tener acceso directo a los datos de la aplicación (bases de datos, nube, archivos de configuración, etc.)

  • No depender de la Interfaz de Usuario.

Un Controlador es considerado “delgado” cuando:

  • Actualiza el Modelo cuando el usuario interactúa con la Vista

  • Actualiza la Vista cuando hay cambios en el Modelo

  • No muestra datos directamente

  • No tiene acceso directo a los datos de la aplicación

  • No contiene reglas de validación ni lógica de negocio.

Una Vista es considerada “tonta” cuando:

  • Muestra los datos contenidos en el Modelo

  • Permite que el usuario interactúe con ella

  • Puede realiza solamente un mínimo procesamiento de datos con el fin de mostrarlos al usuario

  • No almacena datos

  • No tiene acceso directo a los datos de la aplicación

  • No contiene reglas de validación ni lógica de negocio.

¿Cómo Implementar MVC con Python?

De modo general el patrón MVC requiere de la implementación de tres clases, algo que no es muy difícil de suponer. La clase Controlador inicializa las instancias del Modelo y de la Vista; la Vista debe recibir una referencia del Controlador para poder comunicarse con él y hacerle llegar las peticiones del usuario; el Controlador por su parte, puede acceder libremente a todos los atributos y métodos de la interfaz pública del Modelo y de la Vista. Finalmente se definirá un cuarto elemento, el llamado “código cliente”, que definirá una instancia del Controlador y lo ejecutará. Todo esto parece complicado en teoría, por tanto, nada mejor que un ejemplo práctico de cómo hacerlo empleando Python y Tkinter:

file: mvc.py

# -*- coding: UTF-8 -*-

"""Show MVC pattern with Python and Tkinter."""

from random import choice

from tkinter import *

class View:
    """Implement the app View."""

    def __init__(self, parent, controller):
    """Class initializer."""
    # Get a reference to the Controller
    self.controller = controller
    # Build the GUI
    self.greetings_label = Label(parent, text='')
    self.greetings_label.pack()
    self.greetings_button = Button(parent, text='Say Hello')
    self.greetings_button.pack()
    # Connect with the Controller
    self.greetings_button.configure(
        command=self.controller.on_greetings_button_clicked)

    def show_greeting(self, greeting):
        """Show greeting to the user."""
        self.greetings_label['text'] = greeting

class Controller:
    """Implement the app Controller."""

    def __init__(self, parent):
        """Class initializer."""
        # Create the View and Model inside the Controller (Composition)
        self.view = View(parent, self) # Pass a Controller's reference to View
        self.model = Model()

    def get_greeting(self):
        """Get greeting from the Model."""
        # Ask the Model for a greeting
        greeting = self.model.get_greeting()
        return greeting

    def on_greetings_button_clicked(self):
        """Callback for View.greetings_button."""
        # Ask Controller for a greeting
        greeting = self.get_greeting()
        # Ask the view to show greeting to user
        self.view.show_greeting(greeting)

class Model:
    """Implement the app Model."""

    def __init__(self):
        """Class initializer."""
        # Model data
        self.greetings = ('Hello Python Devs!',
                          'Hello World!',
                          'Hello Python Scouts Readers!',
                          'Hello Python MVC Design Pattern!')

    def get_greeting(self):
        """Return a random greeting."""
        return choice(self.greetings)

if __name__ == '__main__':

    # Client Code

    root = Tk()  # Create the root wdow

    ctrl = Controller(parent=root)  # Initialize the Controller

    root.mainloop()

Si ponemos el código anterior en un archivo .py y lo ejecutamos como:

$ python3 mvc.py

Veremos en pantalla una pequeña aplicación con interfaz Tkinter y si presionamos continuamente el botón “Say Hello”, veremos que aparecen varios saludos de forma aleatoria.

En este ejemplo vemos claramente como cada clase realiza su trabajo y únicamente su trabajo. La Vista recibe el click del usuario sobre el botón “Say Hello”. Este evento está enlazado con el método View.on_greetings_button_clicked, quien hace una llamada al Controlador que a su vez se auxilia del Modelo para obtener el saludo a mostrar. El Modelo se encarga de almacenar los saludos, de procesarlos y de devolverlos al Controlador.

Es posible implementar el patrón MVC pasando instancias de la Vista y el Modelo en el momento de la creación de la instancia del Controlador de la forma:

# Client Code

model = Model()

view = View(parent)

ctrl = Controller(model, view)

Esta variante prescinde del empleo de la Composición (Composition) y hace más difícil pasar una referencia del Controlador a la Vista, aunque no imposible. La implementación en este caso sería un poco diferente, pero esto se lo dejamos al lector como un ejercicio de práctica, pero antes le dejamos un Tip: Implementar en la Vista un método View.get_controller_ref() al que le pasaremos como parámetro la instancia que hemos creado del Controlador.

Lecturas Recomendadas

Para profundizar en el estudio del Patrón de Diseño MVC y de algunos otros, recomendamos la lectura del Capítulo 9. “Model-View-Controller – Compound Patterns” del libro “Learning Python Design Patterns.”, Segunda Edición por Chetan Giridhar, publicado por la Editorial “Pakt Publishing”. También pueden referirse al Capítulo 8. “The Model-View-Controller Pattern” del libro “Mastering Python Design Patterns” por Sakis Kasampalis, publicado por la Editorial “Pakt Publishing”.

Bien, esto es todo por ahora, si este artículo te resultó interesante y/o útil, compártelo para que otros también puedan acceder a él. Déjanos tus comentarios y podremos mejorar nuestros contenidos. Ahh, y muchas gracias por ser un lector asiduo de este Blog.

Nos vemos,

lpozo

12 comentarios

Ir al formulario de comentarios

    • Cesar en 10 julio, 2018 a las 4:20 pm

    Hola, una critica constructiva 🙂
    En el funcionamiento, pareces estar describiendo el patrón MVVM (Model–view–viewmodel o Modelo-Vista-VistaModelo), es quizá una cuestión de interpretación, en MVC el controlador pasa el modelo a la vista y es a partir de éste (el modelo) que la vista se actualiza, pero cuando leo como que me da a entender que es el controlador el que le indica a la vista los cambios a hacer.

    Saludos.

    1. Fijate que la idea es que la Vista no debe manipular directamente el Modelo, de lo contrario no necesitamos el Controlador y sería realmente el MVVM sin la C. La Vista en MVC debe recibir la información del modelo a través del Controlador y luego la muestra, solo eso. Realmente es un patrón con muchas variantes e implementaciones y dar una receta definitiva es complicado. Acá traté de simplificarlo para transmitir la idea central. Es más, creo que el código dice más que el texto del post. Te propongo que dejes en un comentario las modificaciones al código que relejen tu visión del MCV y así aprendemos todos.
      Saludos,
      lpozo

        • Cesar en 12 julio, 2018 a las 7:34 pm

        En el MVC la vista no “manipula el modelo”, pero si obtiene los datos de éste, el controlador sigue siendo importante porque permite desacoplar la interfaz gráfica (vista), la lógica de la aplicación (controlador) y la lógica del negocio (modelo). Claro está que esto no es una camisa de fuerza y se pueden hacer variaciones. Este artículo trata sobre el tema: https://pdfs.semanticscholar.org/41a3/3127ac74f126d6ae13a49431983fbda6f7cf.pdf y en este otro hay una comparacion entre MVC y MVP (en aplicaciones web) bastante buena https://arxiv.org/pdf/1408.5786.pdf

        Saludos.

        1. El problema es que hay mucha teoría sobre esto, pero es como que no hay un acuerdo entre los autores sobre quién hace qué cosa y sobre todo cómo la hace, algo que en ocasiones depende hasta del lenguaje. Creo que la idea central es el principio de “Separación e Responsabilidad”, ya la implementación puede variar sutilmente, unos hablan de MVP, otro de MVVM y de variantes de estos, en fin, hay tela por donde cortar. No sé si existirá la verdad absoluta en esto. Revisaré los artículos que me propones, de todos modos el post está basado en la bibliografía que recomiendo al final de la entrada, aunque coincido contigo en que no es un camisa de fuerza. Personalmente y por lo que he leído sobre el tema opino que el término MVC parece haberse convertido en un término genérico para identificar este tipo de patrones, debido quizás a la proliferación de nomenclaturas diferentes para para identificar cosas casi iguales.
          saludos,
          lpozo

  1. Hola Leodanis un saludo, estaba revisando un poco Github y ya me instalé AngrySearch, muy buena, se me parece como Everything en Windows…..si te vi como contribuidor…eso es muy bueno para el desarrllo del software cubano demostrando que de aquí salen muy buenos programadores también…
    @CEPAJ

    1. AngrySearch es un proyecto interesante, ojala tuviera más atención porque potencialidades tiene. He hecho algunas contribuciones aunque no muy trascendentales, porque realmente el tiempo no me sobra. Es un proyecto en el que se pueden hacer muchas cosas, empezando por ordenar mejor el código. Gracias por el reconocimiento…
      saludos,
      lpozo

    • myth en 16 julio, 2018 a las 2:58 pm

    Realmente estas cosas son tan importantes a la hora de desarrollar??

    1. Si te soy sincero debo decirte que son más que importantes, medulares. De hecho, si no conoces la terminología, los patrones que existen y qué hace cada uno, difícilmente lograrás encajar en un equipo profesional de desarrollo. Te sentirás totalmente perdido cuando te digan: ese problema podemos resolverlo implementando un “Strategy” o un “Observer”, o el patrón que proceda. Además, que hay de productivo en inventar nuevamente la rueda. Si ya existe una solución genérica a un tipo de problema determinado, por qué no usarla si ya está probada. Es importante conocerlos, saber cómo funcionan y cómo los podemos implementar, esto nos dará mucha más visión a la hora de resolver cualquier problema.
      saludos,
      lpozo

        • Persona en 18 julio, 2018 a las 1:47 pm

        Es broma, realmente hay patrones que no les encuentro mucho sentido y también creo que enfrascarse mucho en usarlos termina complejizando el código más allá de lo necesario, pero cosas como observer o flyweight son realmente geniales (aunque un poco obvias).

        Por cierto, conoces a algún dibujante que esté interesado en unirse a proyecto de videojuego, 2D y pixelado??

        1. Es cierto, a veces pueden complejizar el código, pero casi siempre nos muestran el camino más corto y mejor pensado.
          Y no, no conozco a ningún dibujante como para lo que me preguntas…
          saludos,
          lpozo

  2. soy algo novato para no decir del todo,, porque ya he creado mis propias tools en python pero estoy repasando step for step y necesito tutoriales que esten claros
    me los puedes hacer llegar al correo 2d.virtus.star@gmail.com

    1. Ok, veré qué puedo hacer.
      saludos,
      lpozo

Los comentarios han sido desactivados.