Model View Controller Pattern (MVC)

di Claudio De Sio Cesari


-Introduzione

Il pattern in questione è molto famoso ma è spesso utilizzato con superficialità degli sviluppatori. Ciò è probabilmente dovuto alla sua complessità, dal momento che stiamo parlando di una vera e propria "composizione di pattern". Venne introdotto nel mondo del software per la costruzione di interfacce grafiche con Smalltalk-80, ma oggi deve gran parte della sua fama a Java. L'MVC è stato infatti utilizzato per la struttura di alcuni componenti Swing, e soprattutto è coerente con l'architettura Java 2 Enterprise Edition (J2EE).
Questo documento è liberamente ispirato, per quanto riguarda la sua struttura, alla descrizione fornita proprio dal catalogo dei pattern J2EE (Java Blueprints).

-Contesto

L'applicazione deve fornire una interfaccia grafica (GUI) costituita da più schermate, che mostrano vari dati all'utente. Inoltre le informazioni che devono essere visualizzate devono essere sempre quelle aggiornate [1].

-Problema

L'applicazione deve avere una natura modulare e basata sulle responsabilità, al fine di ottenere una vera e propria applicazione component - based. Questo è conveniente per poter più facilmente gestire la manutenzione dell'applicazione. Per esempio ai nostri giorni, con la massiccia diffusione delle applicazioni enterprise, non è possibile prevedere al momento dello sviluppo, in che modo e con quale tecnologia gli utenti interagiranno con il sistema (WML?, XML?, WI-FI?, HTML?). Appare quindi chiaro il bisogno di un'architettura che permetta la separazione netta tra i componenti software che gestiscono il modo di presentare i dati, e i componenti che gestiscono i dati stessi.

-Forze

-Soluzione e struttura

L'applicazione deve separare i componenti software che implementano il modello delle funzionalità di business, dai componenti che implementano la logica di presentazione e di controllo che utilizzano tali funzionalità. Vengono quindi definiti tre tipologie di componenti che soddisfano tali requisiti:
- il Model, che implementa le funzionalità di business
- la View: che implementa la logica di presentazione
- il Controller: che implementa la logica di controllo
La seguente fig. 1, rappresenta un diagramma di interazione, che evidenzia le responsabilità dei tre componenti.



Fig. 1: "MVC: diagramma di interazione"





-Partecipanti e responsabilità

-Collaborazioni

In fig. 2 viene evidenziata mediante un diagramma delle classi la vera natura del pattern MVC. In pratica, View e Model sono relazionati tramite il pattern Observer dove la View "osserva" il Model. Ma il pattern Observer caratterizza anche il legame tra View e Controller, ma in questo caso è la View ad essere "osservata" dal Controller. Ciò supporta la registrazione dinamica al runtime dei componenti. Inoltre il pattern Strategy potrebbe semplificare la possibilità di cambiare la mappatura tra gli algoritmi che regolano i processi del Controller e le interazioni dell'utente con la View [2].

Fig. 2: "MVC: diagramma delle classi"


Evidenziamo ora solo due dei possibili scenari che potrebbero presentarsi utilizzando un applicazione MVC-based: la richiesta dell'utente di aggiornare dati e la richiesta dell'utente di selezionare una schermata, rispettivamente illustrate tramite diagrammi di sequenze nelle figure 3 e 4.



Fig. 3: "Scenario aggiornamento dati"


Dalla figura 3 evidenziamo il complesso scambio di messaggi tra i tre partecipanti al pattern, che benché possa sembrare inutile a prima vista, garantisce pagine sempre aggiornate in tempo reale all'utente.



Fig. 4: "Scenario selezione schermata"


Nella figura 4 vengono enfatizzati i ruoli di View e Controller. La View infatti non decide quale sarà la schermata richiesta, delegando ciò alla decisione del Controller (che grazie al pattern Strategy può anche essere anche cambiato dinamicamente al runtime), piuttosto si occupa della costruzione e della presentazione all'utente della schermata stessa.

-Codice d'esempio

Nell'esempio presentato di seguito, viene implementata una piccola applicazione che simula una chat, ma che funziona solo in locale, allo scopo di rappresentare un esempio semplice di utilizzo del pattern MVC. È un esempio didattico e quindi si raccomanda al lettore di non perdersi nei dettagli inutili, ma si consiglia piuttosto, di concentrarsi sulle caratteristiche del pattern. Nella figura 5, è rappresentato il diagramma delle classi della chat dal punto di vista dell'implementazione.





La classe Chat definisce il main che semplicemente realizza lo start up dell'applicazione, così come descritto dal diagramma di sequenza in figura 6.



La classe ChatView definisce due metodi setup1() e setup2(), per realizzare due schermate (molto simili in realtà, ma è solo un esempio). Essa definisce anche due classi interne anonime che fungono da listener. I listener una volta notificati, vanno a delegare all'oggetto (o agli oggetti) ChatController (registratisi in fase di start up come observer della View) mediante codice cicli di notifica come il seguente:


public void itemStateChanged(ItemEvent e) {
  ChatController con;
  for (int i = 0; i < chatObserversVector.size(); i++) {
    con = (ChatController)chatObserversVector.get(i);
    con.processSelectionAction(e.getStateChange());
  }
}

Di seguito è riportata l'intera classe Chat Controller:

public class ChatController implements ChatObserver {
  private ChatModel model;
  private ChatView view;
  private int messageNumber = 0;

  public ChatController(ChatView view, ChatModel model) {
    this.view = view;
    this.model = model;
    view.attach(this);
  }

  public void update() {
    messageNumber++;
    System.out.println(messageNumber);
  }

  public void processSubmitAction(String msg) {
    model.addMessage(msg);
  }

  public void processSelectionAction(int display) {
    view.showDisplay(display);
  }
}

Si può notare come in questo esempio, il metodo update() non faccia altro che incrementare un contatore per contare messaggi, mentre la vera logica di controllo è implementata mediante i metodi (che potrebbero essere metodi strategy, ma in questo caso abbiamo semplificato) processSubmitAction() e processSelectionAction().

Per avere un quadro più completo riportiamo la classe ChatModel per intero (Per scaricare l'intero codice in file zip clicca qui):

import java.util.*;

public class ChatModel implements ChatObservable {
  private Vector messages;
  private Vector forumObserversVector = new java.util.Vector();

  public ChatModel() {
    messages = new Vector();
  }

  public void addMessage(String msg) {
    messages.add(msg);
    inform();
  }

  public String getMessages() {
    int length = messages.size();
    String allMessages = "";
    for (int i = 0; i < length; ++i) {
      allMessages += (String)messages.elementAt(i)+"\n";
    }
    return allMessages;
  }

  public void attach(ChatObserver forumObserver){
    forumObserversVector.addElement(forumObserver);
  }

  public void detach(ChatObserver forumObserver){
    forumObserversVector.removeElement(forumObserver);
  }

  public void inform(){
    java.util.Enumeration enumeration = forumObservers();
    while (enumeration.hasMoreElements()) {
      ((ChatObserver)enumeration.nextElement()).update();
    }
  }

  public Enumeration forumObservers(){
    return ((java.util.Vector) forumObserversVector.clone()).elements();
  }
}

-Conseguenze

-Conclusioni

Il pattern MVC, introduce una notevole complessità all'applicazione, ed è sicuramente non di facile comprensione. Tuttavia il suo utilizzo si rende praticamente necessario in tantissime applicazioni moderne, dove le GUI sono insostituibili. Non conviene avventurarsi alla scoperta di nuove interazioni tra logica di business e di presentazione, se una soluzione certa esiste già.


NOTE

  1. Questo punto non è solitamente valido per architetture come J2EE dove le GUI non sono costituite da applicazioni, ma da pagine HTML.

  2. Che si tratti di un pattern che ne contenga altri, risulta abbastanza evidente. Ma nella sua natura originaria l'MVC comprendeva anche l'implementazione di altri pattern come il Factory Method per specificare la classe Controller di default per una View, il Composite per costruire View, ed il Decorator per aggiungere altre proprietà (per es. lo scrolling).


HOME

JAVA 2

OOA & OOD

WEB & SOFTWARE

CONTATTI