Qual è l'approccio corretto per creare un'applicazione attorno a una libreria?

6

Ho una libreria che definisce i messaggi. Nella mia particolare istanza, è un codice generato automaticamente da un XSD che utilizza JAXB (Java). I messaggi possono essere molto complessi, con alcuni membri come oggetti e quegli oggetti contenenti altri oggetti. Gli oggetti sono sia classi che enumerazioni. La libreria è un singolo file JAR senza dipendenze, indicato come componente riutilizzabile per le applicazioni Java. L'idea è che qualsiasi applicazione Java che ha bisogno di inviare o ricevere questi messaggi utilizzerà questa libreria per farlo. Al momento, sono definiti 10 messaggi, ma esiste un numero elevato di tipi di dati (classi ed enumerazioni) definiti anche nella libreria contenuti nei messaggi.

L'esigenza immediata è per un'applicazione grafica che consente all'utente di costruire i messaggi nel formato specificato e quindi pubblicarli in modo appropriato tramite una connessione di rete. Ciò significa che l'utente sarebbe in grado di creare i 10 messaggi e popolare i vari campi che vi entrano. Il risultato è una stringa XML conforme allo schema che può essere pubblicata in un'applicazione di ascolto. L'applicazione di ascolto genera anche messaggi che sono anche definiti nell'XSD e nella libreria in base allo schema e che devono essere ricevuti.

È auspicabile anche essere in grado di creare una versione da riga di comando di questa applicazione che possa essere sottoposta a script. Questa versione della riga di comando non è ben definita, ma potrebbe essere interattiva (con prompt) o semplicemente argomento della riga di comando guidata per pubblicare i messaggi.

Quale sarebbe l'approccio migliore per creare la mia applicazione intorno a questa libreria?

Mi vengono in mente due approcci:

Il primo approccio è un wrapper attorno alla libreria che fa parte della build dell'applicazione. Questo wrapper sarebbe quasi una duplicazione della libreria JAXB, ma non richiamerebbe gli oggetti dati generati fino a quando richiesto. Sarebbe un builder che fornirebbe anche una convalida e forse una semplificazione interfaccia per alcuni dei componenti dei messaggi. Questo potrebbe essere utile, dal momento che la libreria JAXB non ha un concetto di convalida fino a quando gli elementi non vengono smistati. Anche se puoi marshall a un gestore predefinito al contrario del tuo formato di output come un file o un flusso, ma ciò non sembra molto utile poiché i messaggi che ricevi dagli errori di convalida non sono esattamente user-friendly. In questo approccio, la GUI, l'interfaccia utente testuale e l'interfaccia della riga di comando interagirebbero tutti con questo modello di dati dell'applicazione.

Il secondo approccio sarebbe quello di organizzare le mie interfacce utente in diversi pacchetti. I pacchetti della GUI fornirebbero elementi dell'interfaccia utente che corrispondono ai campi di ciascun messaggio. Le regole di convalida dall'XSD sarebbero applicate come regole di convalida a ciascun campo, usando cose come InputVerifier s , caselle combinate, caselle di controllo e altri elementi che impediscono i dati non validi prima che vengano persino passati al modello dati. L'interfaccia utente del testo fornisce essenzialmente la stessa cosa, ma leggendo e scrivendo sullo standard input, output e flussi di errore. Sospetto che in queste implementazioni le classi di input corrispondessero alle classi del modello di dati da 1 a 1: ciascuna classe di input sarebbe responsabile della raccolta e della convalida degli input dell'utente necessari per costruire un singolo elemento di dati (una classe nel modello di dati fornito dalla libreria JAXB). Ho il sospetto che l'interfaccia utente grafica e la GUI possano condividere le classi di base o le interfacce che ciascuna delle classi UI può ereditare per consentire che vengano passate nello stesso controller per leggere e produrre l'oggetto appropriato dal modello di dati. Un'interfaccia della riga di comando probabilmente userebbe un parser per gli argomenti della riga di comando per raccogliere l'input, assicurarsi che ci sia tutto , convalidare tutti i campi e quindi eseguire le trasmissioni o le ricezioni. Sarebbe implementato in modo molto diverso rispetto alle interfacce utente interattive.

Personalmente mi sto appoggiando al secondo approccio, ma sospetto che ci possa essere un'altra strategia migliore là fuori.

    
posta Thomas Owens 14.03.2015 - 02:00
fonte

2 risposte

4

L'interfaccia per creare questi messaggi è la stessa sia nell'applicazione GUI che nell'interfaccia della riga di comando. Ad esempio, entrambe le applicazioni possono:

  • Aggiungi elementi
  • Elementi di aggiornamento dettagliati nel messaggio
  • Elimina elementi
  • Convalida i messaggi

Progetterei prima questa parte. Progettare i comportamenti che si desidera essere in grado di fare, quindi chiamare le chiamate API appropriate nella classe di messaggistica. Hai discusso lungamente la convalida dei dati: il codice di convalida andrebbe tutto all'interno del modello di dati. Non preoccuparti di come l'utente verrà informato dei messaggi non validi ancora; puoi lanciare ValidationException s che viene catturato in seguito nella progettazione.

Una volta che questo modello di dati funziona nel modo desiderato, è possibile allegare qualsiasi tipo di interfaccia desiderata che possa chiamare questi metodi del modello di dati.

Questa è essenzialmente l'opzione 2, ma la caratteristica distintiva è l'ordine in cui esegui il lavoro . Progettando prima il modello di dati, scoprirai le varie operazioni dell'utente che hanno più senso, prima di preoccuparti di disegnare schermate o di selezionare i flag della riga di comando (o se vuoi che lo strumento della riga di comando sia interattivo).

Quando è il momento di progettare la "vista" (definizione MVC della parola), inizia scrivendo interfacce che funzioneranno sia per la riga di comando che per la versione della GUI. Quindi puoi usare JLine o Commons CLI (a seconda di cosa intendi per riga di comando) o qualcos'altro per il precedente, e Swing o JavaFX o qualsiasi altra cosa nel secondo.

    
risposta data 17.03.2015 - 17:46
fonte
1

Ti consiglio di creare l'applicazione in modo tale che sia facile cambiarla se la libreria cambia. Se si utilizzano i componenti della libreria in diverse parti dell'applicazione e la libreria cambia, sarà necessario modificare molte parti dell'applicazione. Nel lavoro, di solito utilizziamo un livello dedicato per l'esecuzione di richieste a servizi esterni (livello consumer) che è strettamente isolato da altre parti dell'applicazione.

Che ne pensi di un mix di entrambi i tuoi approcci? Il tuo primo approccio è in qualche modo simile all'approccio stratificato che ho descritto sopra, mentre il tuo secondo approccio riguarda più la convalida e la riusabilità, il che sembra ragionevole. Puoi fare entrambe le cose mentre pensi a quanto lavoro richiederà per cambiare le tue cose se la libreria cambia? Penso che questo vi fornirà una chiara separazione delle preoccupazioni e renderà la vostra applicazione più facile da mantenere e fornirà livelli appropriati di riutilizzabilità.

Si scrive che si desidera creare pacchetti GUI per ogni messaggio che riassume fino a 10 pacchetti. Immagino tu intenda un pacchetto Java. Avrei combinato i pacchetti in modo che roba simile fosse nello stesso pacchetto. Per esempio. GUI in una, UI della riga di comando in una e livello consumer in una.

Forse tutti questi suggerimenti sono troppo complessi per il tuo caso d'uso. Ti suggerisco di adottare un approccio top-down, creare scheletri o prototipare rapidamente sia la GUI, l'interfaccia utente della riga di comando e l'utilizzo della libreria (ad esempio solo per un messaggio) per vedere cosa è utile.

UPDATE

Considera se le modifiche nella libreria sono solo tecniche mentre la libreria fornisce ancora la stessa funzionalità - ad es. qualcuno ha eseguito il refactoring come cambiare i nomi delle classi, riordinato il codice spostando i campi da una classe all'altra o introdotto nuove classi. Sarai comunque colpito dalle modifiche, ma se utilizzi un wrapper / decoratore, devi solo modificare le cose lì. Puoi sempre utilizzare le interfacce utente esistenti così come sono, devi solo mappare i dati in modo diverso e questo può essere il lavoro dei wrapper.

Se le interfacce utente riflettono al 100% la libreria, è necessario modificare anche le interfacce utente e non si ottiene alcun beneficio dall'utilizzo del wrapper, come indicato. Tuttavia, è possibile utilizzare alcuni client GUI esistenti per la chiamata di servizi Web, ad es. SoapUI che genera un client per te in base al contratto di servizio web (XSD nel tuo caso). Ciò richiede che il contratto segua alcuni standard come WSDL

    
risposta data 15.03.2015 - 20:24
fonte

Leggi altre domande sui tag