Considera software che controlla uno strumento complesso. Periodicamente esegue il polling dello strumento per leggere un gruppo di valori: tensioni, pressioni, percentuale di completamento, contrassegni di avviso, ecc. Immagina che i dati scendano come XML / JSON, o forse qualche forma binaria, tramite USB o Ethernet. Questi dati vengono visualizzati in una finestra di dialogo non modale che l'utente può monitorare. Quella finestra di dialogo potrebbe essere un'interazione a due vie, cioè ha un pulsante "Abort". In Java, probabilmente si dispone di un thread che esegue questo polling, quindi analizza i dati. Molte altre lingue farebbero simili.
Quindi, dove inserire i dati e come?
Da qualche parte nel profondo della finestra di dialogo c'è un pannello all'interno di un pannello che contiene uno slider o un pulsante o un campo di testo per mostrare questi risultati. È del tutto ragionevole che questo dato profondamente sepolto sia il modello THE , il vero e ufficiale archivio del vero stato ufficiale dello strumento? Ad esempio, se la tensione diventa troppo alta e si vuole far apparire un avviso o inviare una e-mail, questo codice deve guardare attraverso gli JPanel nidificati? No.
È ragionevole che il tuo Polling Thread sappia anche come trovare i pulsanti all'interno di quella finestra di dialogo? Dovrebbe saperlo fare (molto mano che saluta il codice errato) getComponent(EAST).getComponent(3).getStatusTextField().setText("4.56 pounds");
Quasi certamente no. Se stai seguendo Law of Demeter, potrebbe diventare un po 'più semplice, getEscapeModuleForCapsule3StatusTextField()
. Ma anche questo crea un sacco di link tra il thread e la GUI. Che cosa succede se vuoi avere anche Android e una versione HTML5 del tuo codice? Cosa succede se il marketing cambia alcuni dei widget in Sliders o Spinners? Che ne dici di una versione europea che usa chilogrammi? Cosa succede se quel campo di tensione è in realtà 3 campi simili su tre diversi JPanel, due sono Text e uno a Spinner?
O.K., ammetto che sto esagerando un po 'i precedenti due problemi.
Soprattutto, che è il motivo principale per cui questo argomento è apparso su JCiP, anche se si lavora su tutti questi problemi e si progettano problemi in modo che il thread di polling possa arrivare ai widget rilevanti, è un dolore nel sedere per modificare il valore, perché Swing è single threaded . Tutte le chiamate provenienti dal thread di polling sono nella discussione sbagliata e devono essere racchiuse in awkward SwingUtilities.invokeLater(new Runnable() { public void run() {// real code here } });
Modello di dati condivisi
In un "Modello di dati condivisi", sei libero di fare le cose in modo discutibilmente molto più naturale. Definisci una classe InstrumentModel, una che abbia senso per la tua azienda e lo strumento, con setter, getter e, oh yeah, limiti assegni rilevanti. Potrebbe causare eventi speciali quando la tensione diventa troppo alta. Questo modello avrà molto più senso per i vostri scienziati e ingegneri interni rispetto a molti livelli di JPanel annidati. Questo modello deve essere fatto per essere sicuro.
Si noti che questo modello ha nessuna conoscenza se Swing, GWT, HTML5 o American Sign Language saranno l'output. È Disaccoppiamento . Il Polling Thread inserisce i dati in InstruementModel. Quindi (o qualcosa) attiva un evento nella GUI - nella forma più semplice, theHugeDialog.repaint();
Nota che in Swing queste richieste di ripetizione sono accodate, quindi, si spera, la tua finestra di dialogo non ridisegni 100s di volte per ogni modifica.
La GUI, in paintComponent()
o simile (ci sono alcuni trucchi), quindi estrae i dati da InstrumentModel. È automaticamente in esecuzione sul thread Swing AWT appropriato , quindi non c'è bisogno di invokeLaters (). Dal momento che hai abilmente reso sicuro il thread InstrumentModel, la lettura dei dati non è in conflitto con i dati di scrittura di PollingThread. Se è presente anche un campo di testo VeryImportantVoltage nella finestra principale dell'applicazione, può essere aggiornato anche da InstrumentModel.
Questo è l'aggiornamento "snapshot" - in pratica, si ridisegna l'intera GUI. Se la GUI è enorme e si stanno aggiornando centinaia di volte al secondo, questo potrebbe essere troppo lento. Quindi si passa a un aggiornamento incrementale in cui vengono aggiornati solo i dati modificati. Questo diventa molto complicato molto rapidamente.