Untitled Document
   
 
Sviluppo delle GUI in Java: ripresentiamo il MVC
di Andrei Adamchik, traduzione di Francesco Saliola

Il paradigma MVC (Model - View - Controller) è una strategia intuitiva e ampiamente accettata nella progettazione UI, si tratti di web o di applicazioni client complesse. In effetti, si tratta di uno standard de facto così ben definito che "l'aderenza al paradigma MVC" è spesso utilizzata come misura della qualità di framework per interfacce utente, e anche come slogan pubblicitario.

L'aspetto tanto attraente nel MVC è che si tratta di un sistema "naturale" per svolgere determinate azioni: è semplicemente molto sensato suddividere il codice per l'interfaccia utente in grafi di oggetti che rappresentano i dati (la componente model), widget specifiche per l'applicazione che effettuino la resa grafica dell'output (le "viste", ossia la componente view) e una serie di azioni eseguite in risposta a cambiamenti nella view o nel model (la componente controller). Si tratta delle tre principali preoccupazioni che consentono di suddividere il codice in tre gruppi in maniera logica, per una più facile comprensione e una più agevole manutenzione dell'applicazione. L'idea risulta intuitiva per chiunque abbia mai scritto un'applicazione che implichi interazione con utenti.


Figura 1

Swing (e AWT) hanno rappresentato i primi casi di MVC usato in Java., sebbene, in maniera inaspettata, Swing rimanga uno dei framework MVC più complicati e meno intuitivi, con poche indicazioni sul modo corretto di usarlo. Questo articolo tratta i problemi di progettazione delle applicazioni con Swing e mostra dove e come applicare i princìpi Model - View - Controller per risolverli.

Nota su JStaple: Tutti gli esempi in questo articolo sono tratti dal progetto JStaple (http://objectstyle.org/jstaple/). JStaple si occupa dei problemi qui discussi ed è ancora in gran parte in una fase di ricerca. È possibile considerare questo articolo come un white paper informale su JStaple.

 

Swing visto da vicino: dove è il Model - View - Controller?
Rinfreschiamo le idee al lettore con alcuni dati relativi a Swing. Internamente, Swing implementa un tipo comune di MVC detto model-delegate, che raggruppa le componenti view e controller in un "delegato UI". Raramente gli sviluppatori hanno a che fare con la parte view/controller quando scrivono delle applicazioni. Al contrario, essi lavorano con ciò che viene definito "componenti". I componenti Swing in sé stessi non fanno parte della triade MVC, ma funzionano piuttosto come mediatori tra model, view e controller.


Figura 2

La maggior parte del codice personalizzato consiste nella creazione di model e nella costruzione di componenti che rappresentino il layout, comunichino con i sottocomponenti e sincronizzino le viste al model. I componenti che risultano da tale programmazione contengono in genere un mix di codice che si occupa dei compiti inerenti la view (p.e.: la disposizione grafica dei sottocomponenti o il disegno), inerenti il controller (eseguire determinate azioni), e dei compiti attinenti al model (come il wrapping degli oggetti del dominio nei modelli personalizzati).

Quindi, se è vero che i componenti Swing svolgono un ottimo lavoro nel separare il look-and-feel dalla logica dell'applicazione, a livello dell'applicazione essi perdono però una suddivisione "pulita" nelle componenti MVC e finiscono per diventare un miscuglio intricato di codice che esegue un certo numero di compiti non collegati. I problemi diventano ancor più grandi nelle applicazioni complesse in cui ciascun componente può contenere decine di sottoelementi, ciascuno dei quali con i suoi requisiti di gestione.

Chi non è convinto che si tratti di un serio problema può dare un'occhiata al codice di esempio di un qualsiasi buon libro su Swing (che dovrebbe mostrare il modo migliore per lo sviluppo in Swing). La classe di un componente custom di una certa complessità occupa di solito dalle 4 alle 8 pagine di codice Java. Nella realtà operativa, i componenti assumono dimensioni addirittura maggiori, dal momento che gli sviluppatori devono gestire molti casi che negli esempi dei libri sono omessi.

Problema n. 1: I componenti dell'applicazione mescolano molto "materiale" non strettamente collegato all'interno della classe di un singolo componente, producendo un codice di difficile comprensione e manutenzione. Seguire i pattern Swing "raccomandati" non produce un'applicazione "pulita" in termini MVC.

 

Modelli personalizzati
I dati e le operazioni su tali dati arrivano in genere all'applicazione UI sotto forma di oggetti "di dominio" o "business". Un tipico scopo dell'applicazione è di visualizzare tali dati e di interagire con essi. Gli esempi seguenti mostrano come tale interazione sia implementata in Swing.
Se c'è un array di stringhe e occorre mostrarle in un JComboBox:

String[] choices = ..;

// internally combo box wraps the array into DefaultComboBoxModel
// but as long as we don't have to deal with it, this is OK.
JComboBox combo = new JComboBox(choices);

Niente male; procediamo oltre. Che accadrebbe se c'è un elenco di dipartimenti e occorre mostrarne i nomi consentendo all'utente di selezionare uno di essi dall'elenco? Sembra banale e solo appena più complesso del primo esempio, no? Su, pensateci bene: non è possibile farlo direttamente in Swing, ma occorre superare diversi problemi. Un modo possibile potrebbe essere il seguente:

public class DepartmentsComboModel extends AbstractListModel
implements ComboBoxModel {
protected List departments;
protected Object label;
protected Map departmentsByLabel;

public Object getSelectedItem() {
return label;
}
public void setSelectedItem(Object item) {
this.label = item;
}

public Object getElementAt(int index) {
Department department = (Department)
departments.get(index);
return department.getName();
}

public int getSize() {
return (departments != null) ? departments.size() :
0;
}

public Department getSelectedDepartment() {
if (label == null || departmentsByLabel == null) {
return null;
}
return (Department) departmentsByLabel.get(label);
}

public List getDepartments() {
return departments;
}
public void setDepartments(List departments) {
this.departments = departments;

// index departments by name
departmentsByLabel = new HashMap();
...
fireContentsChanged(this, 0, departments.size());
}

public void setSelectedDepartment(Department department) {
this.label = (department != null) ?
department.getName() :
null;
}
}

È necessaria tutta questa intera classe per svolgere un compito semplice: mostrare una proprietà di un oggetto! Se ci sono altri combo box che devono mostrare diversi tipi di oggetti o le varie proprietà dello stesso tipo di oggetto, sarà necessario creare altre ComboBoxModels, e la storia si fa davvero lunga… La soluzione appena presentata è il modo in cui "si suppone" che debba funzionare il JComboBox ed è MVC puro al 100%. Appare comunque come la cosa più innaturale da fare: se ci si spostasse da JComboBox a JTable, il livello di complessità del modello custom si innalza. Appare chiaro quindi che esiste un "modello del dominio" che riguarda effettivamente gli oggetti di cui ci occupiamo, e anche un "modello" che è quello del MVC: i due model non sono la stessa cosa.

Problema n. 2: I componenti Swing non riescono facilmente ad accedere ai dati a partire da un modello di dominio arbitrario e necessitano di interfacce specifiche per il modello; pertanto gli sviluppatori finiscono per scrivere innumerevoli adattatori per le classi di dominio esistenti.
Aggiornare il model: quando gli eventi diventano problematici
La maggior parte degli elementi dei form con cui si immettono i dati non fanno niente di strano con questi dati. In genere viene richiesto solamente di aggiornare una proprietà di un qualche oggetto del model con il valore immesso, magari effettuando prima anche una validazione. A meno che non sia coinvolto un wrapper per il model, come si è visto prima, la procedura di aggiornamento delle proprietà non è automatica. Un componente deve implementare e installare un listener per eventi widget, e tale listener deve essere conforme a interfacce predefinite. Se desideriamo modificare il nome dei dipartimenti usando un JTextField, l'input utente deve essere catturato usando codice simile al seguente:

final Department department = ...;
final JTextField nameField = ...;
...
nameField.getDocument().addDocumentListener(
new DocumentListener() {

public void insertUpdate(DocumentEvent e) {
department.setName(nameField.getText());
}
public void removeUpdate(DocumentEvent e) {
department.setName(nameField.getText());
}
public void changedUpdate(DocumentEvent e) {
department.setName(nameField.getText());
}
});

E questo codice deve essere copiato e incollato per ciascun campo testo sullo schermo... E va notato che qui non stiamo scrivendo un programma che deve sostituire MS Word, ma vogliamo semplicemente aggiornare la proprietà di un oggetto con il testo digitato da un utente dentro un campo testo. Alla fine ci ritroviamo con un proliferare di classi interne, con problemi di inizializzazione in totale confusione, che infrangono o perlomeno indeboliscono il design OO e che è semplicemente orribile. Lo stesso vale per tutti gli altri widget Swing: JButtons, JTextAreas, etc.

Problema n. 3: I componenti Swing devono registrarsi come listener di eventi anche per i compiti più semplici. Dal momento che ciascun listener deve conformarsi a una interfaccia specifica, il codice viene contaminato da classi interne anonime.

 

Ripulire il tutto: MVC sopra Swing
La discussione condotta sopra suggerisce che l'esperienza dello sviluppatore con Swing è ben lontana dall'ideale. Dal momento che riscrivere Swing è fuori questione, non sarebbe male costruirgli sopra qualcosa che lo renda più usabile. In particolare, richiedono un reale miglioramento le seguenti aree: i componenti necessitano di una scomposizione ulteriore e di un modo semplificato per interagire con il modello di dominio. Ebbene, risolvere questi problemi significa creare ancora un altro framework.

Nota sui framework per le applicazioni: vale la pena notare che qualsiasi applicazione a interfaccia grafica utente più complessa di "Hello World" avrà probabilmente bisogno di infrastrutture extra non fornite direttamente a Swing (o Java). La più importante è un container per l'applicazione, che fornisca una serie coerente di servizi per i componenti. La nozione di application object è qualcosa che manca totalmente in Swing. Implementare una soluzione basata su un container IoC come Spring o Pico dovrebbe indirizzarsi verso questo problema; si tratta tuttavia di un argomento diverso, e per questo l'articolo si concentrerà sul miglioramento del modello a componenti di Swing.


Figura 3

Per affrontare i problemi esposti suggeriamo di suddividere i componenti Swing secondo i princìpi del MVC (i framework web WebObjects e Tapestry affrontano il problema con un approccio molto simile a quello qui illustrato). Nel nostro design, i tradizionali componenti Swing assumono il ruolo di View e vengono privati di tutto il codice che riguarda Model e Controller. La vista comprende solamente la disposizione grafica dei sottocomponenti e/o il disegno. Il Model può essere rappresentato da una classe Java, in maniera che gli oggetti del dominio possano essere impiegati direttamente. La parte più importante è il Controller, che consiste di due parti: una classe contenente tutta la logica custom per il componente e uno strato dichiarativo di collegamento. Il resto dell'articolo mostra il modo in cui le diverse parti contemplate in questo design funzionano insieme, in nell'implementazione del prototipo di JStaple.

 

La View: java.awt.Component
Come accennato sopra, la View è di solito una sottoclasse di java.awt.Component. Può trattarsi di un widget Swing come JButton (non sono richieste ulteriori sottoclassi) oppure di un componente custom. Si tratta di una "vista" dalla prospettiva dell'applicazione ma, sotto tutti gli altri aspetti, si tratta di un normale componente Swing/AWT. Ecco un semplice esempio che dimostra come la vista si occupi solamente della disposizione dei sottocomponenti e non includa alcun listener custom, modello o riferimento diretto ai dati dell'applicazione:

public class MainFrameView extends JFrame {

protected JButton newDepartmentButton;
protected JComboBox departmentsCombo;
protected JLabel departmentsLabel;

public MainFrameView() {

// create widgets
departmentsLabel = new JLabel("Departments:");
newDepartmentButton = new JButton("New Department...");
departmentsCombo = new JComboBox();

getContentPane().setLayout(new BorderLayout());
// layout subcomponents, not shown here, as this is
normal Swing code
// ...

setSize(600, 400);
}

public JButton getNewDepartmentButton() {
return newDepartmentButton;
}

public JComboBox getDepartmentsCombo() {
return departmentsCombo;
}

public JLabel getDepartmentsLabel() {
return departmentsLabel;
}
}


Il Controller: implementare la logica dell'applicazione in STComponent
La parte del controller STComponent è il luogo in cui codificare la logica personalizzata di un componente grafico. Ha la funzione di facciata per un qualsiasi numero di oggetti del dominio che vengano dichiarati come proprietà bean di lettura/scrittura del STComponent. STComponent può inoltre dichiarare diversi metodi action. Ecco un esempio semplificato di STComponent. Analogamente all'esempio di view presentato prima, non contiene particolari listener o modelli, ma semplicemente alcuni oggetti del dominio (questo esempio mostra riferimenti a oggetti persistenti e l'uso di DataContext di Cayenne per l'accesso al database) e metodi action:

public class MainFrame extends BaseComponent {

// declare domain objects needed for this component as ivars
protected DataContext dataContext;
protected List departments;
protected Department selectedDepartment;

public MainFrame(Component view) {
super(view);
}

// simple and "calculated" properties...

public List getDepartments() {
return departments;
}

public Department getSelectedDepartment() {
return selectedDepartment;
}

public void setSelectedDepartment(Department
selectedDepartment) {
this.selectedDepartment = selectedDepartment;
}

public String departmentLabel(Department department) {
return " - " + department.getName();
}

// actions

public void addDepartmentAction() {
// create new department and pass control to the
DepartmentEditor dialog

Department department = (Department) dataContext
.createAndRegisterNewObject(Department.class);
DepartmentEditor editor = new DepartmentEditor(
new DepartmentEditorView(),
this,
department);

// binding a callback action to the dialog.
// bindings are discussed in detail below.
editor.bindOkAction("departmentAddedAction(#actionParameter)");
editor.startupAction();
}

// ....
}

 

Il Controller: collegare tutti gli elementi
Né la vista, né STComponent mostrati sopra contengono codice per comunicare l'una con l'altro e, ovviamente, il modello del dominio è completamente indipendente da entrambi. I compiti di comunicazione sono svolti dallo strato di collegamento (il binding) che gestisce tutti i legami senza bisogno di creare infiniti adattatori personalizzati. Internamente, lo strato di collegamento consiste di adattatori generici per i componenti Swing che consentono "l'inserimento" di certe proprietà del model o di action del controller alle "prese" conosciute. Un altro termine per tale tipo di accoppiamento plug/socket ("spina/presa") è binding ("collegamento"). Nel caso più semplice, un binding stabilisce un canale di dati tra la proprietà "legata" della view e alcune proprietà del model, ma senza la necessità di interfacce speciali per il model o il listener. Allo stesso tempo la View e il Model non hanno consapevolezza l'una dell'altro, dal momento che tutte le comunicazioni sono indirette. Ciò salva la fondamentale esigenza di separazione delle componenti del paradigma MVC.

Ciascun componente è collegato tramite un binding set, ovvero un certo numero di legami predefiniti caratterizzati da nome, alcuni dei quali sono obbligatori, altri facoltativi. L'effettiva implementazione di un binding set viene fornita da JStaple e dipende dalla vista specifica (dal momento che internamente un binding deve usare una qualunque API fornita da Swing, comprese classi interne anonime e model specializzati), ma la API utilizzata all'interno del controller per lavorare con i binding è la stessa, indipendentemente dal meccanismo sottostante. Inoltre, è possibile fare di meglio che connettere semplicemente la proprietà del model a una proprietà della vista. Come sarà mostrato sotto, esistono diversi tipi di binding (p.e.: collegare action di STComponent a certi eventi della view, etc.). I binding sono resi veramente dinamici aggiungendo al mix un linguaggio di script. Per lo script, l'attuale implementazione di JStaple utilizza OGNL.

Lo strato di collegamento è dichiarativo e separato da STComponent. JStaple possiede un prototipo di binding pienamente funzionante che è configurato all'interno di STComponent. Tuttavia, dovrebbe essere facile estrarre tutti i binding in XML separato. In questo modo, i collegamenti possono essere modificati e ricaricati dinamicamente senza effettuare ricompilazioni, oltretutto - ed è ancor più importante - senza contaminare il codice.

Ecco un esempio di binding a un JComboBox che si trova in un componente custom. Dimostra diversi risultati che è possibile ottenere con i collegamenti. Va notato che non c'è alcun bisogno di creare sottoclassi di JComboBox, dal momento che il binding funziona con tutti i widget Swing standard (oltre che con componenti personalizzati).

BindingBuilder builder = new BindingBuilder(controllerObject);
builder.switchToSubview("departmentsCombo");

builder.bindToPullValuesFromModel(STComboBoxBindings.LIST_BINDING,
"departments");
builder.bindToPullValuesFromModel(STComboBoxBindings.LABEL_BINDING,
"departmentLabel(#item)");
builder.bindForTwoWaySync(STComboBoxBindings.SELECTED_VALUE_BINDING,
"selectedDepartment");
builder.bindAction(STComboBoxBindings.ACTION_BINDING,
"showEmployeesAction()");
builder.bindToPullValuesFromModel("visible", "connected");

Adesso addentriamoci nelle singole parti:

BindingBuilder builder = new BindingBuilder(controllerObject);
builder.switchToSubview("departmentsCombo");

Viene creato un BindingBuilder che è semplicemente una classe helper per nascondere i dettagli interni del binding. La seconda riga indica al costruttore che si sta per iniziare la configurazione di una proprietà departmentCombo della vista. Ci si attende che sia un JComboBox.

builder.bindToPullValuesFromModel(STComboBoxBindings.LIST_BINDING, "departments");

Qui viene impostato uno dei binding "standard" di JComboBox. I nomi dei binding standard per i diversi componenti Swing sono definiti nelle corrispondenti interfacce di JStaple. Per esempio, questo e altri binding di JComboBox sono definiti nell'interfaccia STComboBoxBindings. Il secondo parametro per un metodo è il nome della proprietà del model, che in questo caso è "departments". Le proprietà vengono risolte utilizzando STComponent come oggetto "root". Dal momento che il binding è creato usando il metodo "bindToPullValuesFromModel", esso lavora a senso unico, aggiornando automaticamente la view ogni volta che il model cambia.

builder.bindToPullValuesFromModel(STComboBoxBindings.LABEL_BINDING, "departmentLabel(#item)");

La riga sopra mostra come sia facile costruire un'etichetta da mostrare per un determinato oggetto nell'elenco, in una maniera definita dal controller per questa vista specifica. Una stringa, mostrata in un JComboBox non deve essere necessariamente il risultato di department.toString(), o una proprietà della classe Department (sebbene in alcuni casi possa esserlo). È possibile fare di meglio. Con una piccola porzione di script OGNL usato come secondo argomento possiamo delegare all'oggetto controller una decisione sulla stringa da mostrare:

L'effettiva implementazione del metodo departmentLabel da parte del controller potrebbe, per esempio, essere posta come prefisso al nome di un determinato dipartimento separandola con un trattino:

public String departmentLabel(Department department) {
  return " - " + department.getName();
}

Ecco la riga successiva:

builder.bindForTwoWaySync(STComboBoxBindings.SELECTED_VALUE_BINDING, "selectedDepartment");

Questa riga mostra come sincronizzare l'oggetto selezionato tra JComboBox e il model. L'oggetto che viene passato è un Department (dal momento che questo è il tipo di oggetti nell'elenco collegato), non l'etichetta String mostrata nel box combo. Non è necessario che lo sviluppatore effettui una conversione manuale tra Department e l'etichetta string: si tratta di una conversione di cui si occupa JStaple.
Il binding precedente imposta la proprietà Department del controller, ma è possibile anche collegare un metodo action che deve essere invocato ogni volta che ci siano modifiche al dipartimento selezionato. Ecco come è possibile fare:

builder.bindAction(STComboBoxBindings.ACTION_BINDING, "showEmployeesAction()");

L'interfaccia STComboBoxBindings dichiara solo qualche binding specifico per JComboBox. Allo stesso tempo, un tipico JComponent potrebbe possedere decine di proprietà: potrebbe darsi il caso che alcune debbano essere controllate dall'applicazione. Ciò ci conduce a scoprire un'altra interessante caratteristica: il binding a una proprietà arbitraria. L'esempio che segue mostra come impostare un binding che modifica la visibilità di JComboBox sulla base della proprietà "connected" del model:

builder.bindToPullValuesFromModel("visible", "connected");

L'esempio JComboBox sopra riportato non appare più come Swing. Presenta caratteristiche di pulizia e non contiene classi interne anonime o modelli specializzati. Ribadiamo quindi ciò che è possibile ottenere usando i binding.

I binding sono la parte del controller usata per la comunicazione indiretta (p.e.: passare i dati o invocare un'azione) tra

  • a. view e model
  • b. view e STComponent

I binding forniscono un'infrastruttura che consente al design MVC, pulito e gerarchico, di usare Swing, AWT e componenti custom. Ciascun elemento view (vale a dire, qualsiasi widget Swing o custom) può avere una serie predefinita di binding. Anche i componenti utente possono dichiarare binding). Per esempio, una finestra di dialogo può avere due binding: okAction e cancelAction. A seconda del bottone della finestra di dialogo che viene premuto, verrà attivato uno di essi quando la finestra di dialogo sarà chiusa, con la conseguente invocazione del metodo dell'azione collegato dell'oggetto che ha effettuato la chiamata. Tutto questo è possibile senza dover definire interfacce listener speciali o dover conoscere qualcosa su ciò che effettua la chiamata. I binding per un determinato componente sono indipendenti l'uno dall'altro, quindi non c'è la necessità di un model specializzato per ciascun tipo di componente. Al contrario, diverse parti del modello di dominio possono essere collegate tramite differenti binding, con il risultato di una notevole flessibilità.
Se un binding non viene riconosciuto come standard, il nome del binding viene trattato come una proprietà della vista. Dal punto di vista della view, i binding possono essere di tipo pull, push o "a doppia modalità". Le action di STComponent possono essere collegate in maniera semplice, proprio come valori di proprietà. Analogamente ai sistemi basati sugli eventi, il binding disaccoppia la view dal model, sebbene, quanto a questo, il binding vada molto oltre. A differenza che con il MVC basato sugli eventi, i binding non richiedono speciali interfacce per il model o classi interne anonime.

Ci sono altri aspetti in cui il binding può venire in aiuto e che non sono ancora stati esplorati completamente in JStaple. Per esempio, il binding può fornire dei generici punti di aggancio per la validazione dell'input. Dovrebbe essere possibile installare un oggetto validatore che venga invocato ogni volta che un binding spinge un valore dalla view al model. I fallimenti nella validazione possono essere gestiti in maniera consistente, per esempio modificando il colore dell'elemento vista e impostando un messaggio per la validazione.

 

E gli eventi?
Ogni componente in Swing fornisce un modo per registrare i listener interessati alla notifica dei vari "avvenimenti" che si verifichino all'interno del componente. Si tratta di un'ottima funzionalità, dal momento che garantisce grande flessibilità. Tuttavia, l'applicazione nel suo insieme raramente ha necessità di essere messa al corrente che una finestra di spunta è stata riempita o che un testo è stato digitato all'interno di un determinato campo. Tali eventi generati da widget possono essere definiti "a corto raggio": solo il controller corrispondente ha realmente interesse ad essi.

D'altro canto ci sono eventi a livello di applicazione in genere associati con cambiamenti nel model. Sono piuttosto diversi dai normali eventi Swing e sono di solito specifici dell'applicazione. Questi eventi possono comunque avere la loro origine in un click su un bottone o in qualche altra azione nella view, ma è probabile che questo fatto non sia riflesso nell'oggetto evento e non sia importante per i listener. Si tratta degli eventi "a lungo raggio", che possono risultare di interesse per più di un solo componente.

Il comportamento qui suggerito è di sostituire ogni uso esplicito di eventi "a corto raggio" a livello dei componenti con binding per rendere tutto più semplice e flessibile. Ma un'applicazione più complessa dovrebbe comunque essere progettata intorno a eventi a "lungo raggio" che forniscano una comunicazione non troppo stretta tra le varie parti del programma. Ovviamente, è sempre possibile usare insieme al binding anche eventi "a raggio corto", se necessario, dal momento che i binding di JStaple sono semplicemente degli adattatori a una serie standard di widget fornita da Swing.

Nascondere eventi di widget a basso livello è semplicemente una delle funzioni che i binding possono svolgere. Possono anche aiutare con l'innesco di eventi "a lungo raggio": un binding può essere configurato per innescare un evento "a lungo raggio" ogni volta che una vista spinga un valore al model (in JStaple questa funzionalità ancora non è implementata). Questo approccio ha due aspetti positivi: è possibile codificare un componente senza conoscere quali eventi esso genererà (dal momento che ciò è definito dinamicamente dagli utenti del componente a runtime), e non è necessario decorare il modello affinché inneschi eventi in base ai cambiamenti di una proprietà.

 

Framework simili
Scope (http://scope.sourceforge.net/). Nella versione 1.0.* conosciuta dall'autore, Scope contiene molti dei concetti discussi qui sotto il nome comune di MVC gerarchico (Hierarchical Model View Controller, HMVC). Tuttavia, Scope presenta anche diverse differenze: specificamente il design del binding è meno dinamico, non supporta uno script avanzato, e richiede la creazione di sottoclassi di widget Swing standard. Le action e le proprietà sono trattate come elementi separati (detti "controlli" e "selettori"). Sembra che non supporti l'estrazione dei binding in uno strato separato.
Cocoa per Mac OS X. Implementato in Objective C. Esiste un wrapper Java, ma può essere usato solo sul Mac OS X.

 

Conclusioni
L'articolo presenta i principali inconvenienti di Swing che lo rendono così difficile da usare: (1) la mancanza di separazione tra il codice che gestisce gli aspetti interni di Swing e la logica dell'applicazione, e (2) la mancanza di un modo pulito per connettere il model del dominio con i componenti.
La soluzione suggerita è di aggiungere uno strato MVC separato sopra Swing, trattando i componenti Swing come una "view". All'interno di questo strato, vengono usati dei binding dinamici, in cui è possibile inserire degli script, per l'assemblaggio dichiarativo e la comunicazione tra le varie parti correlate dell'applicazione.
Il codice JStaple con tutti gli esempi mostrati in questo articolo può essere scaricato dall'indirizzo http://objectstyle.org/jstaple/.

 

L'autore
Andrei (Andrus) Adamchik è uno dei fondatori e dei principali sviluppatori di Cayenne, un framework di mapping object/relational. Nel suo lavoro come programmatore e architetto di software, ha creato applicazioni enterprise, per un certo numero di aziende del campo logistico, finanziario, multimediale e dell'intrattenimento. Attualmente Andrus è CEO della ObjectStyle LLC, una azienda di consulenze software con sedi a New York e Atlanta. Andrus ha dato inizio al progetto JStaple come prototipo per semplificare il difficile sviluppo in Swing grazie agli strumenti di modellazione di Cayenne.