Python e MVC, una storia tutta da scrivere (Prima parte)

Qualche giorno fa, girovagando per l’Universo, ho scoperto un pacchetto fantastico di cui ignoravo completamente l’esistenza: si tratta di python-gtkmvc, contenente un’interessantissima implementazione di MVC per lo sviluppo in Python di applicazioni GTK+.

Prima di illustrarvi le innumerevoli possibilità offerte dai moduli contenuti nel pacchetto in questione, mi sento in dovere di fornirvi perlomeno un’introduzione a MVC: l’acronimo sta per Model-View-Controller (capita sovente di incontrarlo orribilmente tradotto nella lingua di Dante come Modello-Vista-Controllore) e indica uno dei design pattern maggiormente noti e diffusi nello sviluppo di interfacce grafiche, soprattutto negli ambiti della programmazione web (per la quale è nato), basato sul principio di divisione delle responsabilità fra i componenti che interpretano i tre ruoli fondamentali di un sistema software:

  • Model (modello): rappresenta il modello di dominio (o modello business), contiene lo stato del sistema, definisce le operazioni necessarie per accedervi (logica di business) ed è indipendente dalla strato di UI (user interface).
  • View (vista): definisce l’interfaccia utente per interagire con le entità del modello; può fornire una rappresentazione completa o parziale del dominio.
  • Controller (controllore): crea e gestisce la connessione fra il modello e la UI; è a conoscenza dello stato dell’applicazione e mantiene aggiornata la sua rappresentazione.

Chi ha studiato un minimo di analisi e progettazione del software avrà sicuramente avuto a che fare con il pattern Controller, che delega la gestione e il coordinamento dei messaggi provenienti dall’interfaccia ad un oggetto controllore (FacadeController, UseCaseHandler, ecc.), il quale non deve nè appartenere allo strato di UI nè occuparsi della risposta del sistema alle richieste dell’utente; completamente diverso è il controller MVC, parte integrante dell’interfaccia, controllata e gestita in maniera diretta dallo stesso controllore, che provvede anche all’aggiornamento della vista in base al contenuto del modello.

Chiariti i punti fondamentali, possiamo iniziare a esplorare pygtkmvc. Innanzitutto, installiamolo con:

sudo apt-get install python-gtkmvc python-gtkmvc-doc

Nei repository ufficiali di Ubuntu 8.04 «Hardy Heron» è presente la 1.2.1, mentre l’ultima versione è scaricabile dal mio archivio personale; per aggiungere quest’ultimo alla propria lista dei repository è sufficiente inserire la seguente riga nel proprio /etc/apt/sources.list:
deb http://ppa.launchpad.net/quadrispro/ubuntu hardy main

Una volta installato tutto il necessario, cerchiamo di capire come funziona. Innanzitutto, analizziamo l’esempio fornito con la documentazione, cominciando dal modello definito nel file model.py:

from gtkmvc.model import Model
class MyModel (Model):
    # observable properties:
    __properties__ = { 'counter' : 0 }
    def __init__(self):
        Model.__init__(self)
        return
    pass # end of class

Il codice è molto semplice: viene definita una nuova classe MyModel, che estende la classe base Model, fornita dal framework, nel corpo della quale vengono dichiarati e inizializzati degli attributi osservabili (in accordo con Observer, esiste una letteratura infinita che tratta di tale pattern).

Sistemato il modello, concentriamoci sulla sua rappresentazione e prendiamo in esame l’implementazione realizzata senza l’utilizzo di Glade (fra breve vi spiegherò il motivo), presente nel file view.py:

from gtkmvc.view import View
import gtk

class MyViewNoGlade (View):
    def __init__(self, ctrl):

        # Qui l'interfaccia non viene costruita partendo
        # da un file glade. La registrazione viene ritardata
        # e i widget verranno aggiunti a mano
        # successivamente.
        View.__init__(self, ctrl, register=False)

        # Ecco i widget utilizzati:
        w = gtk.Window()
        h = gtk.VBox()
        l = gtk.Label()
        b = gtk.Button("Press")
        h.pack_start(l)
        h.pack_end(b)
        w.add(h)
        w.show_all()

        # Aggiungiamo tutti i widget che ci interessano,
        # assegnando loro un nome. Supponiamo che sia 
        # necessario accedere solo alla finestra principale,
        #  all'etichetta e al pulsante. I widget vengono
        # aggiunti come in una mappa:
        self['main_window'] = w
        self['label'] = l
        self['button'] = b

        # Ora possiamo procedere alla registrazione
        # della vista. Ciò consente al controller di
        # configurare tutte le connessioni dei segnali
        # e le altre operazioni:
        ctrl.register_view(self)
        return
    pass # end of class

Ho pensato di tradurre i commenti embedded originali in modo da facilitare la comprensione del codice, già molto semplice di suo.

Definita l’interfaccia, non resta che curarne il collegamento con il modello. A tale scopo, nel file ctrl.py viene definita una nuova classe, MyController, che contiene i collegamenti sia alla vista che al modello e ne gestisce la sincronizzazione:

from gtkmvc import Controller
import gtk
class MyController (Controller):
    def __init__(self, model):
        Controller.__init__(self, model)
        # Il controller osserva le proprietà
        # presenti nel modello:
        return
    def register_view(self, view):
        """
        Questo metodo viene richiamato dalla vista,
        una volta pronta alla registrazione. Qui
        colleghiamo il clic del pulsante al metodo
        al quale desideriamo far gestire la risposta.
        Lo stesso discorso vale per il segnale di
        'distruzione' della finestra principale.
        """
        Controller.register_view(self, view)
        # collega i segnali:
        self.view['main_window'].connect('destroy', gtk.main_quit)
        self.view['button'].connect('clicked', self.on_button_clicked)
        # inizializza il testo dell'etichetta:
        self.view[’label’].set_text("%d" % self.model.counter)
        return
        # qui inseriamo i gestori dei segnali:
    def on_button_clicked(self, button):
        self.model.counter += 1 # modifica il modello
        return
    # e qui i metodi di notifica delle
    # modifiche alle proprietà
    # osservabili del modello:
    def property_counter_value_change(self, model, old, new):
        self.view['label'].set_text("%d" % new)
        print "Property 'counter' changed value from %d to %d" % (old, new)
        return
    pass # end of class

Penso che i commenti embedded e la documentazione allegata possano chiarire anche i punti più oscuri del codice illustrato. Ho preferito utilizzare l’esempio no-Glade per un motivo di completezza, in modo da mostrarvi ogni piccolo aspetto implementativo.

Ci fermiamo qui, almeno per ora. Nella prossima puntata vi mostrerò una piccola applicazione d’esempio, completa e funzionante, sviluppata proprio con questo fantastico framework.

Riferimenti

Facebook Twitter Linkedin Plusone Pinterest Email

3 pensieri su “Python e MVC, una storia tutta da scrivere (Prima parte)

  1. Ciao Alessio,
    mi ha fatto molto piacere trovare questo tuo commento sul progetto, che purtroppo non riesco in questi mesi a seguire come vorrei.

    E’ in piano il rilascio della release 2.0, ti invito (insieme ai lettori del tuo blog) iscriverti alla lista del progetto https://lists.sourceforge.net/lists/listinfo/pygtkmvc-users

    In piena linea Free Software sono molto interessato a ricevere feedback (e critiche) riguardo il progetto.

    Ciao e grazie ancora per la recensione.
    roberto

    • Roberto, grazie di questo commento!

      Sto preparando la seconda parte dell’articolo, con un piccolo programma dimostrativo.

      Se hai tempo dai un’occhiata Installation Report Generator, anche lì ho usato pygtkmvc.

  2. Pingback: Alessio Treglia » MVC e Python + GTK, seconda parte

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *