MVC (Model, View, Controller) est un modèle d'organisation du code dans une application pour améliorer la maintenabilité.
Imaginez un photographe avec son appareil photo en studio. Un client lui demande de prendre une photo d'une boîte.
Les architectures non-MVC ont tendance à être étroitement intégrées. Si la boîte, le contrôleur et la caméra étaient un seul et même objet, il faudrait alors séparer, puis reconstruire à la fois la boîte et la caméra chaque fois que nous souhaitions obtenir une nouvelle vue. En outre, prendre la photo serait toujours comme essayer de prendre un selfie - et ce n'est pas toujours très facile.
bwaha a écrit:
L'auteur fait référence à mvctree.py dans wxPython en tant qu'exemple de conception MVC. Cependant, je suis encore trop vert et je trouve cet exemple particulier trop complexe et je ne comprends pas la séparation recommandée par l'auteur.
MVC est tout au sujet de la séparation des préoccupations.
Le modèle est responsable de la gestion des données du programme (données privées et données client). Le View / Controller est chargé de fournir au monde extérieur les moyens d'interagir avec les données client du programme.
Le modèle fournit une interface interne (API) permettant aux autres parties du programme d'interagir avec lui. Le View / Controller fournit une interface externe (GUI / CLI / formulaire Web / IPC de haut niveau / etc.) permettant à tout ce qui se trouve en dehors du programme de communiquer avec lui.
Le modèle est responsable du maintien de l'intégrité des données du programme, car si elles sont corrompues, la partie est terminée. La vue / le contrôleur est responsable du maintien de l'intégrité de l'interface utilisateur, en s'assurant que toutes les vues de texte affichent des valeurs mises à jour, en désactivant les éléments de menu qui ne s'appliquent pas au focus actuel, etc.
Le modèle ne contient pas de code de vue / contrôleur; pas de classes de widgets graphiques, pas de code pour la disposition des boîtes de dialogue ou la réception des entrées de l'utilisateur. La vue / le contrôleur ne contient aucun code de modèle; pas de code pour valider les URL ou effectuer des requêtes SQL, ni d'état d'origine non plus: toutes les données détenues par les widgets servent uniquement à des fins d'affichage et représentent uniquement les vraies données stockées dans le modèle.
Maintenant, voici le test d’une véritable conception MVC: le programme doit en principe être entièrement fonctionnel même sans vue / contrôleur attaché. OK, le monde extérieur aura du mal à interagir avec elle sous cette forme, mais tant que l'on connaît les incantations appropriées de l'API modèle, le programme conservera et manipulera les données normalement.
Pourquoi est-ce possible? Eh bien, la réponse simple est que tout cela est dû au faible couplage entre les couches Modèle et Vue / Contrôleur. Cependant, ce n'est pas l'histoire complète. La clé de tout le modèle MVC est la direction dans laquelle ces connexions vont: TOUTES les instructions vont de la vue / contrôleur au modèle. Le modèle ne dit JAMAIS à la vue / au contrôleur quoi faire.
Pourquoi? Parce que dans MVC, la vue / le contrôleur est autorisé à en savoir un peu plus sur le modèle (en particulier, l’API du modèle), mais le modèle n’est pas autorisé à connaître quoi que ce soit à propos de la vue / du contrôleur.
Pourquoi? Parce que MVC consiste à créer une séparation claire des préoccupations.
Pourquoi? Pour éviter que la complexité du programme ne devienne incontrôlable et que le développeur ne soit pas englouti. Plus le programme est volumineux, plus le nombre de composants de ce programme est important. Et plus il y a de connexions entre ces composants, plus les développeurs ont de la difficulté à maintenir / étendre / remplacer des composants individuels, ou même à suivre le fonctionnement de l'ensemble du système. Posez-vous la question suivante: quand vous regardez un diagramme de la structure du programme, préférez-vous voir un arbre ou un berceau de chat? Le modèle MVC évite ce dernier en interdisant les connexions circulaires: B peut se connecter à A, mais A ne peut pas se connecter à B. Dans ce cas, A correspond au modèle et B à la vue / contrôleur.
En passant, si vous êtes pointu, vous remarquerez un problème avec la restriction «à sens unique» qui vient d'être décrite: comment le modèle peut-il informer la vue / le contrôleur des modifications apportées aux données utilisateur du modèle lorsque le modèle n'est même pas autorisé à le faire? savez-vous que la vue / le contrôleur, ne vous faites pas oublier de lui envoyer des messages? Mais ne vous inquiétez pas: il existe une solution à cela, et c'est plutôt chouette même si cela semble un peu détourné au début. Nous y reviendrons dans un instant.
Concrètement, un objet View / Controller peut alors, via l'API du modèle, 1. indiquer au modèle de faire certaines choses (commandes d'exécution) et 2. au modèle de lui donner des choses (renvoyer des données). La couche View / Controller
transmet les instructions à la couche Model et extrait les informations de la couche Model.
Et c'est là votre premier exemple de MyCoolListControl va mal, car l'API pour cette classe exige que l' information soit poussé
en elle, de sorte que vous êtes de retour à avoir un couplage bidirectionnel entre les couches, il ne respecte pas les règles MVC et vous le dumping de retour dans la l'architecture du berceau du chat que vous tentiez [vraisemblablement] d'éviter en premier lieu.
Au lieu de cela, la classe MyCoolListControl doit suivre le flux, en extrayant les données dont elle a besoin à partir de la couche ci-dessous, quand elle en a besoin. Dans le cas d'un widget de liste, cela signifie généralement de demander combien de valeurs il y a, puis de demander chacun de ces éléments, car c'est à peu près la façon la plus simple et la plus lâche de le faire et donc de minimiser le couplage. Et si le widget veut, par exemple, présenter ces valeurs à l'utilisateur dans un bel ordre alphabétique, alors c'est sa responsabilité; et sa responsabilité, bien sûr.
Maintenant, un dernier casse-tête, comme je l'ai déjà indiqué: comment garder l'affichage de l'interface utilisateur synchronisé avec l'état du modèle dans un système basé sur MVC?
Voici le problème: de nombreux objets View ont un état, par exemple une case à cocher peut être cochée ou décochée, un champ de texte peut contenir du texte modifiable. Cependant, MVC exige que toutes les données utilisateur soient stockées dans la couche Modèle. Par conséquent, toutes les données conservées par d'autres couches à des fins d'affichage (l'état de la case à cocher, le texte actuel du champ de texte) doivent par conséquent être une copie subsidiaire de ces données de modèle principales. Mais si l'état du modèle change, la copie de la vue de cet état ne sera plus exacte et devra être actualisée.
Mais comment? Le modèle MVC empêche le modèle d'insérer une nouvelle copie de ces informations dans la couche de vue. Zut, cela n'autorise même pas le modèle à envoyer un message à View pour lui dire que son état a changé.
Enfin presque. D'accord, la couche modèle n'est pas autorisée à parler directement à d'autres couches, car cela nécessiterait de savoir quelque chose à propos de ces couches, ce que les règles MVC empêchent. Cependant, si un arbre tombe dans une forêt et que personne ne l'entend, cela produit-il un son?
La solution, voyez-vous, est de configurer un système de notifications, en fournissant à la couche Modèle un endroit où elle peut annoncer à personne en particulier qu’elle vient de faire quelque chose d’intéressant. Les autres couches peuvent ensuite envoyer des auditeurs avec ce système de notification pour écouter les annonces qui les intéressent. La couche Modèle n'a pas besoin de savoir qui écoute (ou même si quelqu'un écoute!); il ne fait que publier une annonce puis l'oublie. Et si quelqu'un entend cette annonce et a envie de faire quelque chose par la suite - comme demander au Modèle de nouvelles données pour qu'il puisse mettre à jour son affichage à l'écran - alors tant mieux. Le modèle répertorie uniquement les notifications qu'il envoie dans le cadre de la définition de son API. et ce que quelqu'un d'autre fait avec cette connaissance est à eux.
MVC est préservé et tout le monde est heureux. Votre infrastructure d'application peut bien fournir un système de notifications intégré, ou vous pouvez écrire le vôtre sinon (voir le "modèle d'observateur").
...
Quoi qu'il en soit, espérons que cela aide. Une fois que vous avez compris les motivations de MVC, les raisons pour lesquelles les choses sont faites ainsi commencent à prendre un sens, même si, à première vue, elles semblent plus complexes que nécessaire.
À votre santé,
a