Perché Qt utilizza in modo improprio la terminologia di modello / visualizzazione?


104

Penso che la terminologia utilizzata in Qt con i controlli modello / vista sia imperfetta. Nella loro pagina di spiegazione affermano di aver semplificato l'MVC in MV unendo View e Controller e stanno dando la seguente immagine:

immagine che spiega Qt MVC

Comunque penso, hanno chiamato erroneamente i ruoli degli oggetti e penso che,

  1. Ciò che chiamano View with merged Controller è in realtà solo View.
  2. Quello che chiamano Modello è in realtà solo Controller.
  3. Se vuoi davvero avere un modello, sarebbe da qualche parte dove si trovano i loro "dati".

Sto parlando del modo normale e sano di utilizzare il componente modello / visualizzazione Qt nella tua app. Ecco i motivi:

  1. Questo è in genere un componente Qt che viene utilizzato così com'è, senza aggiungere alcuna logica del controller specifica ai tuoi oggetti)
  2. Questo non è certo un modello, solo perché dovresti implementare diversi metodi Qt come rowCount, columnCount, data ecc. Che non hanno nulla a che fare con il tuo modello. In effetti ci sono metodi di modello tipici trovati nei controller. Ovviamente, puoi implementare sia la logica del controller che quella del modello qui, ma prima sarebbe una progettazione del codice piuttosto scadente e in secondo luogo dovresti unire Controller e Model, non Controller e View come affermano.
  3. Come detto nel motivo 2. se si desidera separare la logica del modello, sicuramente non è il riquadro blu sull'immagine, ma piuttosto il riquadro tratteggiato "Dati" (che comunica con Dati reali ovviamente).

Qt è sbagliato nella loro terminologia o sono solo io che non capisco? (BTW: Il motivo per cui non è una questione accademica è che ho iniziato a codificare il mio progetto seguendo la loro denominazione e ho presto scoperto che il codice chiaramente non è corretto. È stato solo dopo che ho capito che avrei dovuto non provare a mettere la logica del modello in quello che chiamano modello)


1
MFC ha stabilito lo standard per il modello / visualizzazione in due parti con CDoc e CView - non c'è motivo per cui un particolare MVC sia "corretto"
Martin Beckett

@Martin B: darò un'occhiata a MFC, tuttavia, anche se ci sono diversi modelli MVC, penso che dovrebbero essere coerenti nella loro terminologia e penso di aver presentato argomenti validi, perché la terminologia utilizzata non è coerente in questo caso particolare. Affermano semplicemente di aver combinato View e Controller, ma penso che sia semplicemente fuorviante nel caso. Non credo che esista un modello MVC in cui tutta la logica specifica dell'applicazione, che si tratti di presentazione o logica del modello, deve essere inserita in un oggetto chiamato Modello.
gorn

1
@Martin B: Anche sotto la terminiology qt tutti i modelli hanno un'API comune che non ha nulla a che fare con la struttura del modello, ma ha tutto a che fare con la struttura generale del controller, il che è chiaramente segno che non è giusto chiamarlo modello. Non sto dicendo che esiste un modello MVC corretto, ma non significa che qualsiasi cosa possa essere chiamata modello MVC. Forse è difettoso anche in MFC e posso dargli un'occhiata, ma mi interessa di più che Qt lo faccia bene, quell'MFC che non intendo usare. Hai qualche buon collegamento in cui viene spiegata la separazione del modello MFC / vista?
gorn

1
La terminologia MVC non è affatto concordata all'unanimità, quindi la tua domanda potrebbe essere considerata argomentativa. Molti saranno comunque d'accordo con l'ottimo lavoro svolto da Martin Fowler ( martinfowler.com/eaaDev/index.html ). Di solito, il controller gestisce l'input dell'utente e, in questo senso, i widget Qt combinano decisamente visualizzazione e controller.
Arnold Spence

1
Capisco che MVC abbia molti gusti, ma non significa che qualsiasi cosa possa essere MVC. Qt ha tagliato il traguardo e ho fornito diversi motivi. Martin Fowler spiega diversi tipi di MVC, ma nessuno dei due è abbastanza simile a ciò che Qt pronuncia MVC. Il più simile è martinfowler.com/eaaDev/PresentationModel.html , ma questo distingue tra Presentation Model = Controller (interazione utente) parte e Model (data logic). Quindi, sebbene non esista una definizione precisa di MVC, Qt non ne segue nessuna. Se puoi darmi un collegamento a tale definizione, fallo.
gorn

Risposte:


78

Sono d'accordo con te sul fatto che la denominazione di Qt sia fuorviante. A mio parere, tuttavia, il problema non è solo di Qt, ma è condiviso da tutti i framework che ci consentono di aderire al principio di separazione delle preoccupazioni durante l'implementazione delle nostre interfacce utente. Quando qualcuno presenta una struttura del genere e trova un buon modo per tenere separate le "cose", si sente sempre obbligato ad avere moduli che chiamano "Modello" e altri che chiamano "Visualizza". Negli anni ho lavorato con questi framework:

  • MFC
  • Qt
  • Swing
  • SWT
  • WPF con MVVM

Se confronti il ​​modo in cui i termini "Modello" e "Visualizza" sono usati in questi framework e quali responsabilità hanno le classi in "Visualizza", "Modello" e "Controller" (se ce n'è uno), lo farai scoprire che ci sono differenze molto grandi. Sarebbe certamente utile fare un confronto tra i diversi concetti e terminologie, in modo che le persone che passano da un framework all'altro abbiano la possibilità di rimanere sani di mente, ma ciò richiederebbe molto lavoro e ricerca. Una buona lettura è la panoramica di Martin Fowler .

Poiché ci sono così tante idee diverse su come può apparire un pattern MVC, qual è quella corretta? A mio parere, le persone che hanno inventato MVC dovrebbero essere rivolte a quando vogliamo sapere come dovrebbe essere implementato "correttamente". Nel documento originale Smalltalk si dice:

La visualizzazione gestisce l'output grafico e / o testuale della porzione di visualizzazione bitmap allocata alla sua applicazione. Il controller interpreta gli input del mouse e della tastiera dall'utente, comandando al modello e / o alla vista di cambiare come appropriato. Infine, il modello gestisce il comportamento e i dati del dominio dell'applicazione, risponde alle richieste di informazioni sul suo stato (solitamente dalla vista) e risponde alle istruzioni per cambiare stato (solitamente dal controller).

Alla luce di ciò, risponderei così alle tue tre principali preoccupazioni:

  1. Infatti un componente Qt "gestisce l'output [...] grafico", e "interpreta gli input del mouse e della tastiera", quindi potrebbe effettivamente essere chiamato View e Controller uniti rispetto alla definizione sopra.
  2. Sono d'accordo che sei / saresti costretto a fondere Controller e Model (sempre rispetto alla definizione di cui sopra).
  3. Sono d'accordo, di nuovo. Il Modello dovrebbe gestire solo i dati del dominio dell'applicazione . Questo è ciò che chiamano "dati". Chiaramente, occuparsi di righe e colonne, ad esempio, normalmente non ha nulla a che fare con il nostro dominio delle applicazioni.

Dove ci lascia? A mio parere, è meglio capire cosa significa veramente Qt quando vengono usati i termini "Modello" e "Visualizza" e utilizzare i termini a loro modo mentre programmiamo con Qt. Se continui a essere infastidito, ti rallenterà, e il modo in cui le cose sono impostate in Qt consente un design elegante, che pesa più delle loro convenzioni di denominazione "sbagliate".


2
Direi che il delegato è il controller di Qt, poiché i delegati ricevono e inviano l'input al modello, che aggiorna la visualizzazione tramite segnali.
Peregring-lk

82

Risposta breve

L'MVC di Qt si applica solo a una struttura dati . Quando si parla di un MVC applicazione non si deve pensare QAbstractItemModelo QListView.

Se si desidera un'architettura MVC per l'intero programma, Qt non dispone di un framework modello / visualizzazione così "enorme". Ma per ogni elenco / albero di dati nel tuo programma puoi usare l'approccio Qt MVC che ha effettivamente un controller nella sua vista. I dati sono all'interno o all'esterno del modello; questo dipende dal tipo di modello che si sta utilizzando (sottoclasse del proprio modello: probabilmente all'interno del modello; ad esempio QSqlTableModel: esterno (ma forse memorizzato nella cache) del modello). Per mettere insieme i tuoi modelli e le tue viste, usa le tue classi che implementano la logica di business .


Risposta lunga

Approccio e terminologia modello / visualizzazione di Qt:

Qt fornisce visualizzazioni semplici per i loro modelli. Hanno un controller integrato: selezionare, modificare e spostare gli elementi sono qualcosa che nella maggior parte dei casi un controller "controlla". Ovvero, interpretare l'input dell'utente (clic e spostamenti del mouse) e impartire i comandi appropriati al modello.

I modelli di Qt sono infatti modelli che hanno dati sottostanti. I modelli astratti ovviamente non contengono dati, poiché Qt non sa come archiviarli. Ma si estende una QAbstractItemModel alle proprie esigenze aggiungendo i vostri contenitori di dati alla sottoclasse e rendendo l'interfaccia modello di accesso ai dati. Quindi in effetti, e presumo che non ti piaccia, il problema è che devi programmare il modello, quindi il modo in cui i dati vengono acceduti e modificati nella tua struttura dati.

Nella terminologia MVC, il modello contiene sia i dati che la logica . In Qt, sta a te includere o meno parte della tua logica di business all'interno del tuo modello o metterla all'esterno, essendo una "vista" a sé stante. Non è nemmeno chiaro cosa si intende per logica: selezionare, rinominare e spostare elementi? => già implementato. Fare calcoli con loro? => Mettilo all'esterno o all'interno della sottoclasse del modello. Memorizzare o caricare dati da / a un file? => Inseriscilo nella sottoclasse del modello.


La mia opinione personale:

E 'molto difficile fornire una buona e sistema generico MV (C) per un programmatore. Poiché nella maggior parte dei casi i modelli sono semplici (ad es. Solo elenchi di stringhe), Qt fornisce anche un QStringListModel pronto per l'uso. Ma se i tuoi dati sono più complessi delle stringhe, sta a te decidere come rappresentare i dati tramite l'interfaccia di visualizzazione / modello Qt. Se hai, ad esempio, una struttura con 3 campi (diciamo persone con nome, età e sesso) potresti assegnare i 3 campi a 3 colonne diverse oa 3 ruoli diversi. Non mi piacciono entrambi gli approcci.

Penso che il framework modello / vista di Qt sia utile solo quando si desidera visualizzare strutture dati semplici . Diventa difficile da gestire se i dati sono di tipo personalizzato o strutturati non in un albero o in un elenco (ad esempio un grafico). Nella maggior parte dei casi, gli elenchi sono sufficienti e anche in alcuni casi un modello dovrebbe contenere una sola voce. Soprattutto se si desidera modellare una singola voce con attributi diversi (un'istanza di una classe), il framework modello / vista di Qt non è il modo giusto per separare la logica dall'interfaccia utente.

Per riassumere, penso che il framework di visualizzazione / modello di Qt sia utile se e solo se i tuoi dati vengono visualizzati da uno dei widget del visualizzatore di Qt . È totalmente inutile se stai per scrivere il tuo visualizzatore per un modello che contiene solo una voce, ad esempio le impostazioni dell'applicazione, o se i tuoi dati non sono di tipo stampabile.


Come ho usato il modello / vista Qt all'interno di un'applicazione (più grande)?

Una volta ho scritto (in un team) un'applicazione che utilizza più modelli Qt per gestire i dati. Abbiamo deciso di creare un DataRoleper contenere i dati effettivi che erano di un diverso tipo personalizzato per ogni diversa sottoclasse del modello. Abbiamo creato una classe di modello esterna chiamata Modelcontenente tutti i diversi modelli Qt. Abbiamo anche creato una classe di visualizzazione esterna chiamata Viewholding le finestre (widget) che sono collegate ai modelli all'interno Model. Quindi questo approccio è un Qt MVC esteso, adattato alle nostre esigenze. Entrambe Modele le Viewclassi stesse non hanno nulla a che fare con Qt MVC.

Dove abbiamo messo la logica ? Abbiamo creato classi che eseguivano i calcoli effettivi sui dati leggendo i dati dai modelli di origine (quando sono cambiati) e scrivendo i risultati nei modelli di destinazione. Dal punto di vista di Qt, queste classi logiche sarebbero viste, poiché si "connettono" ai modelli (non "vista" per l'utente, ma una "vista" per la parte logica di business dell'applicazione).

Dove sono i controllori ? Nella terminologia MVC originale, i controller interpretano l'input dell'utente (mouse e tastiera) e danno comandi al modello per eseguire l'azione richiesta. Poiché le viste Qt interpretano già l'input dell'utente come rinominare e spostare elementi, ciò non era necessario. Ma ciò di cui avevamo bisogno era un'interpretazione dell'interazione dell'utente che andasse oltre le visualizzazioni Qt.


La cosa più irritante è che devi implementare classi Qt Model totalmente diverse a seconda della vista che desideri. Un modello per una visualizzazione elenco non supporterà correttamente una visualizzazione albero e viceversa. Un modello MVC canonico può supportare una pletora di diversi tipi di visualizzazione.
smerlin

3
@ smerlin: non penso che sia corretto. Sia QListView che QTreeView richiedono solo un'interfaccia QAbstractItemView, il che significa che una sottoclasse personalizzata di quella, o una classe concreta come QStandardItemModel dovrebbe soddisfare quel requisito per entrambi. Puoi guidare un albero ed elencare un modello.
jdi

1
@jdi: ci sono casi in cui i tuoi dati sono sia un elenco che un albero ... ad esempio potresti visualizzare il tuo file system come un albero o tutti i file come un elenco. I modelli Qts non lo consentono correttamente. Un'implementazione di QAbstractItemModel che supporta le visualizzazioni ad albero, consente solo di visualizzare tutti i file / directory nella directory principale come elenco, ma non è possibile visualizzare tutti i file come elenco. E non dire che la visualizzazione dei dati dell'albero come elenco non possa essere utile. Ad esempio, puoi ad esempio ordinarli facilmente per trovare il file con la dimensione massima del file se visualizzi i tuoi file come un elenco, le viste ad albero non lo consentirebbero.
smerlin

1
Detto questo, il modello proxy è più qualcosa della tua vista (poiché modifica il modo in cui i dati vengono visualizzati ) e quindi dovrebbe appartenere alla tua vista. Se leggi la mia risposta lunga: nella Viewclasse "grande" dovresti aggiungere il modello proxy, che ha il modello ad albero come modello sottostante ed è utilizzato dalla visualizzazione elenco del tuo file system. Come stai dicendo: non dovrebbero esserci due modelli per gli stessi dati. Mai! (Ma i modelli proxy non contano come modelli separati.)
leemes

1
@SamPinkus Questo perché non c'è un chiaro o no a questa domanda. Inoltre, ci sono diverse implementazioni di QAbstractItemModel, alcune delle quali sono modelli nel senso di MVC e altre no.
leemes

12

La terminologia non è giusta o sbagliata, è utile o inutile.

Potresti cambiare un po 'la domanda e chiedere perché Qt non è più compatibile con MVC. La risposta è che i primi sviluppatori di Qt credono che il disaccoppiamento di V da C nelle applicazioni GUI crei sia V che C male. Il design di QWidget cerca di semplificare il legame tra l'interoperabilità dell'input del mouse e le decisioni sull'output dei pixel e puoi vedere come questa non sia la strada verso MVC.


Capisco il tuo punto e fondamentalmente vorrei chiederti perché Qt non è più compatibile con MVC, ma è molto difficile da fare quando la terminologia MVC utilizzata nella documentazione di Qt è DIVERSA da quella che MVC è normalmente utilizzata (come ho spiegato nella domanda). E quando c'è una terminologia ampiamente usata e qualcuno la usa in modo molto diverso dal resto del mondo, tendo a pensare che non solo sia inutile, ma che sia semplicemente SBAGLIATA e confusa (quella confusione mi ha portato a porre la domanda nel primo posto). Sarei molto interessato se avessi collegamenti a queste cose in discussione o spiegate da qualche parte. Grazie
gorn

Non posso dire nulla sul motivo per cui i documenti Qt ora parlano di MVC nel modo in cui lo fanno. Ho lasciato Trolltech molto tempo fa e sono perplesso da alcune delle cose che sono state fatte alla documentazione da quando me ne sono andato. (Sul mio blog a volte mi lamento un po 'su questo, però.)
arnt

Hai qualche idea su come la terminologia MVC sia stata concordata in Qt. È stato utilizzato durante la scrittura del codice o solo successivamente durante il processo di documentazione.
gorn

Non abbiamo usato la parola "MVC" nella documentazione di Qt durante il mio periodo alla Trolltech. In generale penso che sia meglio documentare quello che c'è, non scrivere quello che non c'è. Tuttavia, oltre gitorious puoi scoprire chi ha aggiunto quel testo e aggiungere direttamente quella persona.
arnt

1
Un commento diverso. Abbiamo discusso di MVC durante la progettazione e la prima frase di implementazione di Qt (quando Trollech era una società di tre persone), e abbiamo valutato un toolkit GUI che utilizzava MVC "correttamente", non ricordo il suo nome. La nostra opinione era che quel toolkit fosse terribile da usare e che MVC fosse in gran parte la ragione di ciò.
arnt

3

Poiché la funzione Model è quella di rispondere alle richieste di informazioni, penso che non ci sia nulla di sbagliato nella definizione di metodi come rowCount, columnCountecc. Penso che Model sia una sorta di wrapper per l'origine dati (non importa quale sia la tabella SQL o solo un array) , fornisce dati in forma standard e la definizione dei metodi dipende dalla struttura dell'origine dati.


2

Credo che la loro terminologia sia corretta ... anche se nelle applicazioni reali trovo che possa essere molto facile sfocare le linee tra modello, vista e controller a seconda del livello di astrazione: la vista di un livello può essere il modello di un livello superiore.

Sento che la confusione nasce dalla loro classe QAbstractModelItem. Questa classe non è un elemento del modello, ma piuttosto è un'interfaccia per un modello. Per rendere le loro classi di visualizzazione interfacciate con il modello, dovevano creare un'interfaccia astratta generica al modello. Tuttavia, un modello può essere un singolo articolo, un elenco di articoli, una tabella di 2 o più dimensioni di articoli, ecc. quindi la loro interfaccia deve supportare tutte queste variazioni di modello. Certo, questo rende gli elementi del modello piuttosto complessi e il codice collante per farlo funzionare con un modello reale sembra allungare un po 'la metafora.


Sebbene io sia d'accordo con te con la classe QAbstractModelItem, penso anche che anche senza questa complicazione il loro MVC sia denominato erroneamente. Potresti spiegare perché pensi che la loro terminologia sia corretta. Mi piacerebbe sapere perché non ho ragione in nessuno dei miei tre argomenti.
gorn

0

Penso che ... Quello che chiamano Modello è in realtà solo Controller.

No, il loro "modello" non è sicuramente un controller.

Il controller è la parte dei controlli visibili all'utente che modificano il modello (e quindi modificano indirettamente la vista). Ad esempio, un pulsante "elimina" fa parte del controller.

Penso che ci sia spesso confusione perché molti vedono qualcosa come "il controller modifica il modello" e pensano che questo significhi che le funzioni mutanti sul loro modello, come un metodo "deleteRow ()". Ma nel classico MVC, il controller è specificamente la parte dell'interfaccia utente. I metodi che modificano il modello fanno semplicemente parte del modello.

Da quando MVC è stato inventato, la sua distinzione tra controller e view è diventata sempre più tesa. Pensa a una casella di testo: ti mostra del testo e ti consente di modificarlo, quindi è visualizzazione o controller? La risposta deve essere che fa parte di entrambi. Ai tempi in cui lavoravi su una telescrivente negli anni '60 la distinzione era più chiara - pensa a ed- ma questo non significa che le cose andassero meglio per l'utente allora!

È vero che il loro QAbstractItemModel è di livello piuttosto più alto di quanto sarebbe normalmente un modello. Ad esempio, gli elementi al suo interno possono avere un colore di sfondo (un pennello tecnicamente), che è un attributo decisamente visivo! Quindi c'è un argomento che QAbstractItemModel è più simile a una vista e i tuoi dati sono il modello. La verità è che si trova a metà strada tra i classici significati di vista e modello. Ma non riesco a vedere come sia un controller; semmai è il widget QT che lo utilizza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.