Per tenere ben separata la logica applicativa (la "business logic") di un'applicazione dall'interfaccia utente, sono stati ideati diversi modelli (pattern) architetturali, che ci aiutano nel design delle nostre applicazioni. Nel web ha particolare successo il modello a strati (multi-tier), che vede le applicazioni organizzate in tre livelli logici:
| Strato dell'applicazione | Funzione |
|---|---|
| Data logic | si occupa dell'astrazione dei dati e dell'interazione con il database |
| Business logic | è la logica applicativa, manipola i dati e li organizza per la presentazione all'utente |
| Presentation | è l'interfaccia grafica con la quale l'utente interagisce e attraverso la quale invia delle istruzioni alla business logic |
Il livello di "business logic" risponde alle richieste ricevute dall'interfaccia e comunica i risultati delle elaborazioni all'interfaccia stessa cambiandone lo stato. Una variante di questo modello a strati è l'architettura MVC.
MVC
MVC è l'acronimo di Model View Controller ed è un pattern architetturale formalizzato alla fine degli anni '70 con il linguaggio SmallTalk e diventato di moda negli anni '90, ampiamente diffuso per lo sviluppo di interfacce grafiche di software object-oriented.
Le applicazioni Flex sono notoriamente basate su interfaccia grafica, quindi MVC può venirci in aiuto per organizzare lo sviluppo delle nostre rich internet applications, garantendo la separazione dell'interfaccia grafica dalla business logic.
Anche MVC prevede l'organizzazione dell'applicazione in tre livelli:
| Livello | Descrizione |
|---|---|
| Model | Incapsula le strutture dati e garantisce l'attribuzione di un significato ai dati grezzi. Siccome il pattern MVC non prevede un livello dedicato all'interazione con la base dati, è di uso comune introdurre nel livello Model la logica per la comunicazione e le richieste al database |
| View | Si occupa della visualizzazione dei dati e della visualizzazione dell'interfaccia utente |
| Controller | Riceve i comandi dallo strato View e modifica lo stato del model in relazione alle richieste ricevute. Contiene la business logic dell'applicazione |
Per Flex esistono molti framework MVC. I più importanti sono Cairngorm, un framework realizzato esclusivamente per Flex del cui sviluppo si occupa Adobe, e PureMVC, disponibile anche per altri linguaggi e basato sul design pattern Observer. Questi due framework sono molto complessi e risultano inadatti per lo sviluppo di piccole applicazioni Flex.
In questo articolo vedremo come implementare un semplice pattern MVC adatto allo sviluppo di applicazioni di piccole dimensioni.
Una applicazione "normale"
Per il nostro esempio sviluppiamo una semplice applicazione per inserire e rimuovere elementi da una Datagrid. Per rendere chiari i vantaggi di sviluppare un'applicazione con approccio model-view-controller, costruiamo prima un'applicazione mischiando logica applicativa e interfaccia grafica e, successivamente, la ristrutturiamo separando il codice Actionscript (organizzato in classi) dai component MXML.
Di seguito è riportato il codice dell'applicazione, costituita da un singolo file con estensione .mxml.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.utils.ArrayUtil;
import mx.collections.ArrayCollection;
[Bindable]
private var data_list:ArrayCollection = new ArrayCollection();
public function addUser():void
{
if (user_name.text == "" && user_surname.text == "")
return;
data_list.addItem(user_name.text + " " + user_surname.text);
}
public function delUser():void
{
data_list.removeItemAt(userList.selectedIndex);
}
]]>
</mx:Script>
<!-- View -->
<mx:DataGrid x="10" y="102" id="userList" width="302" dataProvider="{data_list}">
<mx:columns>
<mx:DataGridColumn headerText="Elenco nominativi" dataField="user"/>
</mx:columns>
</mx:DataGrid>
<mx:Button label="Aggiungi" id="btn_add" click="addUser()" x="236" y="70"/>
<mx:Button label="Elimina" id="btn_del" click="delUser()" x="164" y="70"/>
<mx:TextInput id="user_name" x="101" y="10"/>
<mx:TextInput id="user_surname" x="101" y="40"/>
<mx:Text text="Nome:" fontWeight="bold" x="51" y="12" />
<mx:Text text="Cognome:" fontWeight="bold" x="29" y="42"/>
</mx:Application>
I dati su cui lavora l'applicazione sono contenuti nella variabile data_list dichiarata con l'istruzione:
Nello stesso file abbiamo anche inserito il codice che realizza l'interfaccia e le operazioni sui dati.
L'applicazione che abbiamo appena sviluppato è funzionante, ma l'approccio utilizzato non ne garantisce una facile estensione
Basti pensare all'eventuale necessità di utilizzare i dati contenuti nella struttura dati data_list
Datagrid
Per questo motivo, si sceglie di complicare la struttura dell'applicazione e di ricorrere ad un'organizzazione del codice in livelli.
Applicare il pattern MVC
Model
Per prima cosa, racchiudiamo i dati della nostra applicazione in una classe che chiamiamo UserListModel. Di seguito è riportato il codice che implementa la classe UserListModel (file UserListModel.as):
Per garantire che ogni modifica effettuata su un membro della classe sia automaticamente trasmessa all'interfaccia, la classe è "marcata" come [Bindable]
UserListModel
Singleton
UserListModel
getInstance()
UserListModel
private
SingletonEnforcer
SingletonEnforcer
Controller
Dopo aver creato il model, ci preoccupiamo di scrivere la classe che deve svolgere il ruolo di Controller. In questa classe dobbiamo racchiudere la logica applicativa: creiamo due metodi, uno per l'inserimento e l'altro per la cancellazione di un elemento dalla lista di nomi presente nel model.
Di seguito è riportato il codice che implementa la classe UserListController:
Il livello controller dovrebbe contenere e gestire la logica applicativa, che nel caso della nostra applicazione è estremamente semplice. Da notare che la classe UserListController
UserListModel
UserListModel.getInstance()
View
L'ultimo passo da compiere per realizzare la nostra applicazione è la realizzazione dell'interfaccia grafica.
L'interfaccia, nel nostro caso, è molto simile a quella che abbiamo già sviluppato in precedenza. Modifichiamo solo gli event handler per gli eventi di click sui pulsanti Aggiungi ed Elimina, che devono ora utilizzare i metodi del controller per cambiare lo stato del model.
Di seguito è riportato il codice che implementa l'interfaccia grafica:
L'oggetto model è definito [Bindable] per garantire l'aggiornamento automatico dell'interfaccia quando ne viene cambiato lo stato.
Come dataProvider della dataGrid è utilizzato il valore di ritorno del metodo getUserList del model, il cui stato cambia quando vengono richiamati i metodi addUserInList e delUserFromList del controller.
Di seguito è riportato l'esempio realizzato:
Conclusioni
La motivazione principale che spinge gli sviluppatori ad organizzare le applicazioni in livelli è quella di garantire la massima coesione e il minimo accoppiamento tra i moduli: ogni classe deve svolgere un insieme definito e limitato di operazioni e deve essere minimizzato il numero di richieste ai metodi di altre classi.
L'applicazione sviluppata è un semplice esempio per capire il funzionamento del pattern MVC, e può essere preso come modello per lo sviluppo di piccole applicazioni. Per applicazioni di grandi dimensioni, invece, è più adatto l'utilizzo di framework MVC quali Cairngorm e PureMVC, che garantiscono un migliore controllo dell'applicazione e un miglior riutilizzo del codice.