web-dev-qa-db-fra.com

Pourquoi Qt utilise-t-il mal la terminologie du modèle / vue?

Je pense que la terminologie utilisée dans Qt avec les contrôles modèle/vue est erronée. Sur leur page d'explication ils déclarent qu'ils ont simplifié le MVC en MV en fusionnant View et Controller et ils donnent l'image suivante:

picture explaining Qt MVC

Cependant, je pense qu'ils ont mal nommé les rôles des objets et je pense que,

  1. Ce qu'ils appellent View avec le contrôleur fusionné est en fait une View uniquement.
  2. Ce qu'ils appellent Model est en fait Controller uniquement.
  3. Si vous voulez vraiment avoir un modèle, ce serait quelque part où se trouvent leurs "données".

Je parle de la façon habituelle et saine d'utiliser le composant Qt model/view dans votre application. Voici les raisons:

  1. Il s'agit généralement d'un composant Qt qui est utilisé tel quel, sans ajouter de logique de contrôleur spécifique à vos objets)
  2. Ce n'est pas un modèle, juste parce que vous devez implémenter plusieurs méthodes Qt comme rowCount, columnCount, data etc. qui n'ont rien à voir avec votre modèle. En fait, il existe des méthodes de modèle typiques trouvées dans les contrôleurs. Bien sûr, vous pouvez implémenter à la fois la logique du modèle Controller et ici, mais d'abord ce serait une conception de code assez mauvaise et deuxièmement vous fusionneriez Controller et Model not Controller et voir comme ils le disent.
  3. Comme dit dans la raison 2. si vous voulez séparer la logique du modèle, ce n'est sûrement pas la boîte bleue sur l'image, mais plutôt la boîte "Data" en pointillés (communiquant avec les vraies données bien sûr).

Qt a-t-il tort dans leur terminologie, ou c'est juste moi qui ne comprends pas? (BTW: La raison pour laquelle ce n'est pas une question académique est que j'ai commencé à coder mon projet après leur dénomination et j'ai vite découvert que le code n'est clairement pas correct. Ce n'est qu'après cela quand j'ai réalisé que je devrais pas essayer de mettre la logique du modèle dans ce qu'ils appellent le modèle)

96
gorn

Je suis d'accord avec vous que la dénomination de Qt est trompeuse. À mon avis cependant, le problème n'est pas le seul de Qt, mais est partagé par tous les cadres qui nous permettent d'adhérer au principe de séparation des préoccupations lors de la mise en œuvre de nos interfaces utilisateur. Lorsque quelqu'un propose un tel cadre et trouve un bon moyen de séparer les "choses", il se sent toujours obligé d'avoir des modules qu'ils appellent "Model" et d'autres qu'ils appellent "View". Au fil des ans, j'ai travaillé avec ces cadres:

  • MFC
  • Qt
  • Balançoire
  • SWT
  • WPF avec MVVM

Si vous comparez la façon dont les termes "modèle" et "vue" sont utilisés dans ces cadres et quelles sont les responsabilités des classes dans la "vue", le "modèle" et le "contrôleur" (s'il y en a un), vous constater qu'il y a de très grandes différences. Il serait certainement utile d'avoir une comparaison des différents concepts et terminologies, afin que les personnes passant d'un cadre à un autre aient une chance de rester saines, mais cela nécessiterait beaucoup de travail et de recherche. Une bonne lecture est celle de Martin Fowler aperç .

Puisqu'il y a tellement d'idées différentes à quoi un modèle MVC peut ressembler, laquelle est correcte? À mon avis, les personnes qui ont inventé MVC devraient être tournées vers quand nous voulons savoir comment il est censé être mis en œuvre "correctement". Dans le papier Smalltalk original il dit:

La vue gère la sortie graphique et/ou textuelle de la partie de l'affichage bitmap allouée à son application. Le contrôleur interprète les entrées de la souris et du clavier de l'utilisateur, en commandant le modèle et/ou la vue à modifier selon les besoins. Enfin, le modèle gère le comportement et les données du domaine d'application, répond aux demandes d'informations sur son état (généralement depuis la vue) et répond aux instructions de changement d'état (généralement depuis le contrôleur).

À la lumière de cela, je répondrais ainsi à vos trois principales préoccupations:

  1. En fait, un composant Qt "gère la sortie [...] graphique" et "interprète les entrées de la souris et du clavier", il pourrait donc être appelé fusionné View and Controller par rapport à la définition ci-dessus.
  2. Je conviens que vous êtes/seriez obligé de fusionner le contrôleur et le modèle (encore une fois en ce qui concerne la définition ci-dessus).
  3. Je suis encore d'accord. Le modèle ne doit gérer que les données du domaine d'application . C'est ce qu'ils appellent des "données". De toute évidence, traiter des lignes et des colonnes par exemple n'a normalement rien à voir avec notre domaine d'applications.

Où cela nous laisse-t-il? À mon avis, il est préférable de comprendre ce que Qt signifie vraiment lorsque les termes "modèle" et "vue" sont utilisés et d'utiliser les termes à leur manière pendant que nous programmons avec Qt. Si vous continuez à être gêné, cela ne fera que vous ralentir, et la façon dont les choses sont configurées dans Qt permet un design élégant - qui pèse plus que leurs "mauvaises" conventions de dénomination.

73
Tilo

Réponse courte

Le MVC de Qt ne s'applique qu'à ne structure de données. Lorsque vous parlez d'un MVC application vous ne devriez pas penser à QAbstractItemModel ou QListView.

Si vous voulez une architecture MVC pour l'ensemble de votre programme, Qt n'a pas un tel modèle/cadre de vue "énorme". Mais pour chaque liste/arborescence de données de votre programme, vous pouvez utiliser l'approche Qt MVC qui a en effet un contrôleur dans sa vue. données se trouve à l'intérieur ou à l'extérieur du modèle; cela dépend du type de modèle que vous utilisez (sous-classe de modèle propre: probablement dans le modèle; par exemple QSqlTableModel: à l'extérieur (mais peut-être mis en cache à l'intérieur) du modèle). Pour assembler vos modèles et vues, utilisez vos propres classes qui implémentent ensuite la logique métier.


Longue réponse

Approche et terminologie du modèle/vue de Qt:

Qt fournit de simples vues pour leurs modèles. Ils ont un contrôleur intégré: la sélection, l'édition et le déplacement des éléments sont quelque chose que dans la plupart des cas un contrôleur "contrôle". C'est-à-dire, interpréter les entrées de l'utilisateur (clics et mouvements de souris) et donner les commandes appropriées au modèle.

Les Qt modèles sont en effet des modèles ayant des données sous-jacentes. Les modèles abstraits ne contiennent bien sûr pas de données, car Qt ne sait pas comment vous souhaitez les stocker. Mais vous étendez un QAbstractItemModel à vos besoins en ajoutant vos conteneurs de données à la sous-classe et en faisant l'interface du modèle accéder à vos données. Donc en fait, et je suppose que vous n'aimez pas cela, le problème est que vous devez programmer le modèle, donc comment les données sont accessibles et modifiées dans votre structure de données.

Dans la terminologie MVC, le modèle contient à la fois données et logique. Dans Qt, c'est à vous de décider si vous incluez ou non une partie de votre logique métier dans votre modèle ou si vous la mettez à l'extérieur, étant une "vue" à part entière. On ne sait même pas ce que l'on entend par logique: sélectionner, renommer et déplacer des éléments? => déjà implémenté. Faire des calculs avec eux? => Mettez-le à l'extérieur ou à l'intérieur de la sous-classe du modèle. Stockage ou chargement de données depuis/vers un fichier? => Mettez-le dans la sous-classe du modèle.


Mon opinion personnelle:

Il est très difficile de fournir un bon et système MV (C) générique à un programmeur. Parce que dans la plupart des cas, les modèles sont simples (par exemple uniquement des listes de chaînes), Qt fournit également un QStringListModel prêt à l'emploi. Mais si vos données sont plus complexes que des chaînes, c'est à vous de décider comment vous souhaitez représenter les données via l'interface modèle/vue Qt. Si vous avez, par exemple, une structure avec 3 champs (disons des personnes avec un nom, un âge et un sexe), vous pouvez affecter les 3 champs à 3 colonnes différentes ou à 3 rôles différents. Je n'aime pas les deux approches.

Je pense que le modèle/cadre de vue de Qt n'est utile que lorsque vous souhaitez afficher structures de données simples. Il devient difficile à gérer si les données sont de types personnalisés ou structurées pas dans un arbre ou une liste (par exemple un graphique). Dans la plupart des cas, les listes sont suffisantes et même dans certains cas, un modèle ne doit contenir qu'une seule entrée. Surtout si vous souhaitez modéliser une seule entrée ayant des attributs différents (une instance d'une classe), le cadre de modèle/vue de Qt n'est pas la bonne façon de séparer la logique de l'interface utilisateur.

Pour résumer, je pense que le cadre de modèle/vue de Qt est utile si et seulement si vos données sont visualisées par l'un des widgets de visualisation de Qt. C'est totalement inutile si vous êtes sur le point d'écrire votre propre visionneuse pour un modèle ne contenant qu'une seule entrée, par ex. les paramètres de votre application ou si vos données ne sont pas de type imprimable.


Comment ai-je utilisé le modèle/vue Qt dans une (plus grande) application?

Une fois, j'ai écrit (en équipe) une application qui utilise plusieurs modèles Qt pour gérer les données. Nous avons décidé de créer un DataRole pour contenir les données réelles qui étaient d'un type personnalisé différent pour chaque sous-classe de modèle différente. Nous avons créé une classe de modèle externe appelée Model contenant tous les différents modèles Qt. Nous avons également créé une classe de vue externe appelée View contenant les fenêtres (widgets) qui sont connectées aux modèles dans Model. Cette approche est donc un Qt MVC étendu, adapté à nos propres besoins. Les classes Model et View elles-mêmes n'ont rien à voir avec le MVC Qt.

Où avons-nous mis le logique? Nous avons créé des classes qui ont effectué les calculs réels sur les données en lisant les données des modèles source (lorsqu'ils ont changé) et en écrivant les résultats dans les modèles cibles. Du point de vue de Qt, ces classes logiques seraient des vues, car elles se "connectent" à des modèles (pas une "vue" pour l'utilisateur, mais une "vue" pour la partie logique métier de l'application).

Où sont les contrôleurs? Dans la terminologie MVC d'origine, les contrôleurs interprètent l'entrée utilisateur (souris et clavier) et donnent des commandes au modèle pour effectuer l'action demandée. Étant donné que les vues Qt interprètent déjà les entrées utilisateur comme renommer et déplacer des éléments, cela n'était pas nécessaire. Mais ce dont nous avions besoin, c'était d'une interprétation de l'interaction utilisateur qui va au-delà des vues Qt.

79
leemes

La terminologie n'est pas bonne ou mauvaise, elle est utile ou inutile.

Vous pourriez changer un peu la question et demander pourquoi Qt n'est pas plus compatible avec MVC. La réponse est que les premiers développeurs de Qt croient que le découplage de V de C dans les applications GUI fait des Vs et des Cs mauvais. La conception de QWidget essaie de simplifier la liaison étroite de l'interpération d'entrée de souris avec les décisions de sortie de pixels, et vous pouvez voir comment ce n'est pas la route vers MVC.

12
arnt

Comme la fonction Model est de répondre aux demandes d'informations, je pense qu'il n'y a rien de mal à définir des méthodes telles que rowCount, columnCount, etc. Je pense que Model est une sorte de wrapper pour la source de données ( quelle que soit la table SQL ou juste un tableau), il fournit des données sous forme standard, et vous devez définir des méthodes en fonction de la structure de votre source de données.

3
Dmitry

Je crois que leur terminologie est correcte ... bien que dans les applications réelles, je trouve qu'il peut être très facile de brouiller les lignes entre le modèle, la vue et le contrôleur en fonction de votre niveau d'abstraction: la vue d'un niveau peut être un modèle de niveau supérieur.

Je pense que la confusion provient de leur classe QAbstractModelItem. Cette classe n'est pas un élément de modèle, mais plutôt une interface avec un modèle. Pour faire l'interface de leurs classes de vues avec le modèle, ils ont dû créer une interface abstraite générique vers le modèle. Cependant, un modèle peut être un seul article, une liste d'articles, un tableau de 2 dimensions d'articles ou plus, etc.; leur interface doit donc prendre en charge toutes ces variations de modèle. Certes, cela rend les éléments du modèle assez complexes, et le code de collage pour le faire fonctionner avec un modèle réel semble étirer un peu la métaphore.

2
Chris Morlier