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

104

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

image expliquant Qt MVC

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

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

Je parle de la manière habituelle et sensée d'utiliser le composant modèle / vue Qt 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 guère un modèle, simplement 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 contrôleur et du modèle ici, mais d'abord, ce serait une conception de code assez mauvaise et deuxièmement, vous fusionneriez contrôleur et modèle et non contrôleur et vue 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 en pointillés "Data" (communiquant avec des données réelles bien sûr).

Qt est-il faux dans sa 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 en suivant leur nom et j'ai vite découvert que le code n'était clairement pas correct. Ce n'est qu'après cela que j'ai réalisé que je devrais pas essayer de mettre la logique du modèle dans ce qu'ils appellent le modèle)

gorn
la source
1
MFC a établi la norme pour le modèle en 2 parties / vue guis avec CDoc et CView - il n'y a aucune raison qu'un MVC particulier soit `` correct ''
Martin Beckett
@Martin B: Je vais jeter un œil à MFC, mais même s'il existe différents modèles MVC, je pense qu'ils devraient être cohérents dans leur terminologie et je pense avoir présenté des arguments valables, pourquoi la terminologie utilisée n'est pas cohérente dans ce cas particulier. Ils déclarent simplement qu'ils ont combiné View et Controller, mais je pense que c'est tout simplement trompeur dans l'affaire. Je ne pense pas qu'il existe un modèle MVC où toute la logique spécifique à l'application, que ce soit la présentation ou la logique du modèle, doit être placée dans un objet appelé Modèle.
gorn
1
@Martin B: Toujours sous la terminologie qt, tous les modèles ont une API commune qui n'a rien à voir avec la structure du modèle, mais tout à voir avec la structure générale du contrôleur, ce qui est clairement signe qu'il n'est pas juste de l'appeler Modèle. Je ne dis pas qu'il existe UN modèle MVC correct, mais cela ne signifie pas que tout peut être appelé modèle MVC. Peut-être qu'il est également défectueux dans MFC et que je peux y jeter un coup d'œil, mais je suis plus intéressé par Qt pour bien faire les choses, ce MFC que je n'ai pas l'intention d'utiliser. Avez-vous un bon lien expliquant la séparation modèle / vue MFC?
gorn
1
La terminologie MVC n'est en aucun cas acceptée à l'unanimité, donc votre question pourrait être considérée comme argumentative. Beaucoup seront cependant d'accord avec l'excellent travail réalisé par Martin Fowler ( martinfowler.com/eaaDev/index.html ). Habituellement, le contrôleur gère les entrées de l'utilisateur et dans ce sens, les widgets Qt combinent très certainement la vue et le contrôleur.
Arnold Spence
1
Je comprends que MVC a de nombreuses saveurs mais cela ne signifie pas que tout peut être MVC. Qt a franchi la ligne d'arrivée et j'ai donné plusieurs raisons. Martin Fowler explique différents types de MVC, mais aucun d'eux n'est assez similaire à ce que Qt prononce MVC. Le plus similaire est martinfowler.com/eaaDev/PresentationModel.html , mais cela fait la distinction entre Presentation Model = Controller (interaction utilisateur) et Model (data logic). Donc, bien qu'il n'y ait pas de définition précise de MVC, Qt ne suit aucun d'entre eux. Si vous pouvez me donner un lien vers une telle définition, veuillez le faire.
gorn

Réponses:

78

Je suis d'accord avec vous que la dénomination de Qt est trompeuse. À mon avis cependant, le problème n'est pas seulement celui de Qt, mais il 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. Quand 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 «Modèle» et d'autres qu'ils appellent «Vue». Au fil des années, j'ai travaillé avec ces frameworks:

  • 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 trouvent qu'il existe de très grandes différences. Il serait certainement utile d'avoir une comparaison des différents concepts et terminologies, afin que les gens qui passent d'un cadre à un autre aient une chance de rester sains d'esprit, mais cela demanderait beaucoup de travail et de recherche. Une bonne lecture est l' aperçu de Martin Fowler .

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

La vue gère la sortie graphique et / ou textuelle de la partie de l'affichage bitmap qui est allouée à son application. Le contrôleur interprète les entrées de la souris et du clavier de l'utilisateur, ordonnant au modèle et / ou à la vue de changer 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 à partir de la vue) et répond aux instructions de changement d'état (généralement du 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 souris et clavier", il pourrait donc en effet être appelé Vue et Contrôleur fusionnés par rapport à la définition ci-dessus.
  2. Je conviens que vous êtes / seriez obligé de fusionner Controller et Model (encore une fois en ce qui concerne la définition ci-dessus).
  3. Je suis d'accord, encore une fois. 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 les lignes et les colonnes par exemple n'a normalement rien à voir avec notre domaine d'applications.

Où nous laisse-t-il? À mon avis, il est préférable de comprendre ce que Qt signifie réellement 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 dérangé, 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.

Tilo
la source
2
Je dirais que le délégué est le contrôleur du Qt, puisque les délégués reçoivent et envoient l'entrée au modèle, ce qui met à jour la vue via des signaux.
Peregring-lk
82

Réponse courte

Le MVC de Qt ne s'applique qu'à une seule structure de données . Lorsque vous parlez d'une application MVC , vous ne devez pas penser à QAbstractItemModelou QListView.

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


Longue réponse

Approche modèle / vue et terminologie de Qt:

Qt fournit des vues simples pour leurs modèles. Ils ont un contrôleur intégré: la sélection, l'édition et le déplacement des éléments sont ce 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 la souris) et donner les commandes appropriées au modèle.

Les modèles de Qt 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 voulez les stocker. Mais vous étendez un QAbstractItemModel à vos besoins en ajoutant vos conteneurs de données à la sous-classe et en créant l'interface du modèle pour 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 les données et la logique . Dans Qt, c'est à vous de décider si vous incluez ou non une partie de votre logique métier à l'intérieur de votre modèle ou si vous la mettez à l'extérieur, étant une «vue» en soi. Ce que l'on entend par logique n'est même pas clair: 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 de modèle. Stocker ou charger des données depuis / vers un fichier? => Mettez-le dans la sous-classe du modèle.


Mon avis personnel:

Il est très difficile de fournir un bon et système MV (C) générique pour 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 voulez les représenter via l'interface modèle / vue Qt. Si vous avez, par exemple, une structure avec 3 champs (disons des personnes avec nom, âge et sexe), vous pouvez attribuer les 3 champs à 3 colonnes différentes ou à 3 rôles différents. Je n'aime pas les deux approches.

Je pense que le cadre modèle / vue de Qt n'est utile que lorsque vous souhaitez afficher des structures de données simples . Cela devient difficile à gérer si les données sont de types personnalisés ou ne sont pas structurées dans un arbre ou une liste (par exemple un graphique). Dans la plupart des cas, les listes suffisent 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 différents attributs (une instance d'une classe), le cadre 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 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 visualiseur pour un modèle ne contenant qu'une seule entrée, par exemple les paramètres de votre application, ou si vos données ne sont pas de types imprimables.


Comment utiliser le modèle / la vue Qt dans une (plus grande) application?

J'ai écrit une fois (en équipe) une application qui utilise plusieurs modèles Qt pour gérer les données. Nous avons décidé de créer un DataRolepour 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 Modelcontenant tous les différents modèles Qt. Nous avons également créé une classe de vue externe appelée Viewcontenant les fenêtres (widgets) qui sont connectées aux modèles à l'intérieur Model. Cette approche est donc un Qt MVC étendu, adapté à nos propres besoins. Les deux Modelet Viewclasses elles - mêmes n'ont rien à voir avec le MVC Qt.

Où avons-nous mis la 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, puisqu'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 originale, les contrôleurs interprètent l'entrée utilisateur (souris et clavier) et donnent des commandes au modèle pour exécuter l'action demandée. Étant donné que les vues Qt interprètent déjà les entrées utilisateur telles que le changement de nom et le déplacement d'éléments, cela n'était pas nécessaire. Mais ce dont nous avions besoin, c'était une interprétation de l'interaction utilisateur qui va au-delà des vues Qt.

leèmes
la source
La chose la plus irritante est que vous devez implémenter des classes de modèle Qt totalement différentes en fonction de la vue souhaitée. Un modèle pour une vue de liste ne prendra pas correctement en charge une vue arborescente et vice versa. Un modèle MVC canonique peut prendre en charge une pléthore de types de vues différents.
smerlin
3
@smerlin: Je ne pense pas que ce soit correct. Un QListView et un QTreeView ne nécessitent qu'une interface QAbstractItemView, ce qui signifie qu'une sous-classe personnalisée de celle-ci, ou une classe concrète comme QStandardItemModel devrait répondre à cette exigence pour les deux. Vous pouvez conduire un arbre et lister un modèle.
jdi
1
@jdi: il y a des cas où vos données sont à la fois une liste et un arbre ... par exemple, vous pourriez souhaiter afficher votre système de fichiers sous forme d'arborescence, ou tous les fichiers sous forme de liste. Les modèles Qts ne le permettent pas correctement. Une implémentation de QAbstractItemModel prenant en charge les vues arborescentes, permet uniquement d'afficher tous les fichiers / répertoires de votre répertoire racine sous forme de liste, mais vous ne pouvez pas afficher tous les fichiers sous forme de liste. Et ne dites pas que l'affichage des données d'arbre sous forme de liste ne peut pas être utile. Par exemple, vous pouvez facilement les trier pour trouver le fichier avec la plus grande taille de fichier si vous affichez vos fichiers sous forme de liste, les arborescences ne le permettraient pas.
smerlin
1
Cela dit, le modèle proxy est plus quelque chose de votre vue (car il modifie la façon dont les données sont vues ) et devrait donc appartenir à votre vue. Si vous lisez ma longue réponse: Dans la "grande" Viewclasse, vous devez ajouter le modèle proxy, qui a le modèle d'arbre comme modèle sous-jacent et qui est utilisé par la vue de liste de votre système de fichiers. Comme vous le dites: il ne devrait pas y avoir deux modèles pour les mêmes données. Jamais! (Mais les modèles proxy ne comptent pas comme des modèles séparés.)
leemes
1
@SamPinkus C'est parce qu'il n'y a pas de oui ou de non clair à cette question. En outre, il existe différentes implémentations de QAbstractItemModel, dont certaines sont des modèles au sens de MVC et d'autres non.
leemes
12

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

Vous pouvez changer un peu la question et demander pourquoi Qt n'est pas plus convivial pour MVC. La réponse est que les premiers développeurs de Qt pensent que le découplage de V de C dans les applications GUI entraîne à la fois des V et des C mauvais. La conception de QWidget essaie de simplifier la liaison étroite entre l'interperation d'entrée de la souris et les décisions de sortie des pixels, et vous pouvez voir comment ce n'est pas la voie vers MVC.

arnt
la source
Je vois votre point de vue et, fondamentalement, je demanderais pourquoi Qt n'est pas plus convivial pour MVC, mais c'est très difficile à faire lorsque la terminologie MVC utilisée dans la documentation de Qt est DIFFÉRENTE de ce que MVC est normalement utilisé (comme je l'ai expliqué dans la question). Et quand il y a une terminologie largement utilisée et que quelqu'un l'utilise très différemment du reste du monde, j'ai tendance à penser que ce n'est pas seulement inutile, mais que c'est tout à fait FAUX et déroutant (cette confusion m'a conduit à poser la question dans le premier endroit). Je serais très intéressé si vous avez des liens avec ces choses qui sont discutées ou expliquées quelque part. Merci
gorn
Je ne peux rien dire sur les raisons pour lesquelles les documents Qt parlent maintenant de MVC comme ils le font. J'ai quitté Trolltech il y a longtemps et je suis déconcerté par certaines des choses qui ont été apportées à la documentation depuis mon départ. (Sur mon blog, je me dis parfois un peu à ce sujet, cependant.)
arnt
Avez-vous une idée de la façon dont la terminologie MVC a été convenue dans Qt. A-t-il été utilisé lors de l'écriture du code, ou seulement plus tard lors du processus de documentation.
gorn
Nous n'avons pas utilisé le mot «MVC» dans la documentation Qt pendant mon séjour chez Trolltech. En général, je pense qu'il est préférable de documenter ce qui est là, pas d'écrire sur ce qui n'y est pas. Cependant, sur gitorious, vous pouvez savoir qui a ajouté ce texte et ajouter cette personne directement.
arnt
1
Un commentaire différent. Nous avons discuté de MVC lors de la conception et de la première phrase d'implémentation de Qt (lorsque Trollech était une société de trois personnes), et nous avons évalué une boîte à outils d'interface graphique qui utilisait MVC "correctement", je ne me souviens plus de son nom. Notre opinion était que cette boîte à outils était terrible à utiliser et que MVC en était en grande partie la raison.
arnt
3

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, columnCountetc. Je pense que Model est une sorte de wrapper pour la source de données (peu importe ce que c'est une 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.

Dmitry
la source
2

Je pense 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 le modèle d'un niveau supérieur.

Je sens que la confusion provient de leur classe QAbstractModelItem. Cette classe n'est pas un élément de modèle, mais plutôt une interface vers un modèle. Pour que leurs classes de vue s'interfacent avec le modèle, ils ont dû créer une interface abstraite générique avec le modèle. Cependant, un modèle peut être un seul élément, une liste d'éléments, un tableau de 2 dimensions ou plus d'éléments, 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.

Chris Morlier
la source
Bien que je sois d'accord avec vous avec la classe QAbstractModelItem, je pense aussi que même sans cette complication, leur MVC est mal nommé. Pourriez-vous expliquer pourquoi vous pensez que leur terminologie est correcte. J'aimerais entendre pourquoi je n'ai raison dans aucun de mes trois arguments.
gorn
0

Je pense que ... Ce qu'ils appellent Model n'est en fait que Controller.

Non, leur «modèle» n'est certainement pas un contrôleur.

Le contrôleur est la partie des contrôles visibles par l'utilisateur qui modifient le modèle (et donc modifient indirectement la vue). Par exemple, un bouton «supprimer» fait partie du contrôleur.

Je pense qu'il y a souvent confusion parce que beaucoup voient quelque chose comme "le contrôleur modifie le modèle" et pensent que cela signifie les fonctions de mutation sur leur modèle, comme une méthode "deleteRow ()". Mais dans MVC classique, le contrôleur est spécifiquement la partie de l'interface utilisateur. Les méthodes qui font muter le modèle font simplement partie du modèle.

Depuis que MVC a été inventé, sa distinction entre contrôleur et vue est devenue de plus en plus tendue. Pensez à une zone de texte: elle vous montre à la fois du texte et vous permet de le modifier, alors est-ce une vue ou un contrôleur? La réponse doit être que cela fait partie des deux. À l'époque où vous travailliez sur un télétype dans les années 1960, la distinction était plus claire - pensez-y ed- mais cela ne signifie pas que les choses allaient mieux pour l'utilisateur à l'époque!

Il est vrai que leur QAbstractItemModel est plutôt de niveau supérieur qu'un modèle ne le serait normalement. Par exemple, les éléments qu'il contient peuvent avoir une couleur d'arrière-plan (un pinceau techniquement), qui est un attribut résolument view-ish! Il y a donc un argument selon lequel QAbstractItemModel ressemble plus à une vue et vos données sont le modèle. La vérité est que c'est quelque part entre les significations classiques de la vue et du modèle. Mais je ne vois pas comment c'est un contrôleur; si quelque chose c'est le widget QT qui l'utilise.

Arthur Tacca
la source