Qu'est-ce qui se passe dans le "Contrôleur" dans "MVC"?


Je pense comprendre les concepts de base de MVC - le modèle contient les données et le comportement de l'application, la Vue est responsable de l'afficher à l'utilisateur et le Contrôleur s'occupe de l'entrée de l'utilisateur. Ce dont je suis incertain, c'est exactement ce que va dans le contrôleur.

Disons par exemple que j'ai une application assez simple (je pense spécifiquement à Java, mais je suppose que les mêmes principes s'appliquent ailleurs). J'organise mon code en 3 paquets appelés app.model, app.view et app.controller.

Dans le package app.model, j'ai quelques classes qui reflètent le comportement réel de l'application. Ces extends Observable et utilisent setChanged() et notifyObservers() pour déclencher la mise à jour des vues le cas échéant.

Le paquet app.view a une classe (ou plusieurs classes pour différents types d'affichage) qui utilise des composants javax.swing pour gérer l'affichage. Certains de ces composants doivent être réinjectés dans le modèle. Si je comprends bien, la vue ne devrait rien avoir à voir avec le commentaires - qui devrait être traitée par le Contrôleur.

Alors, qu'est-ce que je mets réellement dans le contrôleur? Est-ce que je mets le public void actionPerformed(ActionEvent e) dans la vue avec juste un appel à une méthode dans le contrôleur? Si oui, toute validation, etc. doit-elle être effectuée dans le contrôleur? Si oui, comment puis - je renvoyer les messages d'erreur à la Vue-cela devrait-il passer à nouveau par le modèle, ou le contrôleur devrait-il simplement le renvoyer directement à la vue?

Si la validation est effectuée dans la vue, que dois-je mettre dans le Contrôleur?

Désolé pour la longue question, je voulais juste documenter ma compréhension du processus et j'espère que quelqu'un pourra clarifier ce problème pour moi!

Author: victor hugo, 2009-06-19

13 answers

Dans l'exemple que vous avez suggéré, vous avez raison: "l'utilisateur a cliqué sur le bouton 'supprimer cet élément'" dans l'interface devrait simplement appeler la fonction "supprimer" du contrôleur. Le contrôleur, cependant, n'a aucune idée de ce à quoi ressemble la vue, et votre vue doit donc collecter des informations telles que "quel élément a été cliqué?"

Dans une forme de conversation:

View: "Hé, contrôleur, l'utilisateur vient de me dire qu'il voulait que l'élément 4 soit supprimé."
Contrôleur de: "Hmm, après avoir vérifié ses lettres de créance, il est autorisé à le faire... Hey, model, je veux que vous obteniez l'article 4 et que vous fassiez tout ce que vous faites pour le supprimer."
Le Modèle: "Article 4... l'a obtenu. Il est supprimé. De retour à vous, Contrôleur."
Controller : "Ici, je vais collecter le nouvel ensemble de données. Revenons à vous, view."
View: "Cool, je vais montrer le nouvel ensemble à l'utilisateur maintenant."

À la fin de cette section, vous avez une option: soit la vue peut faire une demande distincte, "donnez-moi l'ensemble de données le plus récent", et soyez donc plus pur, ou le contrôleur renvoie implicitement le nouvel ensemble de données avec l'opération "delete".

 456
Author: Andres Jaan Tack, 2010-08-23 18:47:53

Le problème avec MVC est que les gens pensent que la vue, le contrôleur et le modèle doivent être aussi indépendants que possible les uns des autres. Ils ne pensent pas - une vue et un contrôleur sont souvent entrelacés - comme M(VC).

Le contrôleur est le mécanisme d'entrée de l'interface utilisateur, qui est souvent emmêlé dans la vue, en particulier avec les interfaces graphiques. Néanmoins, view est en sortie et controller est en entrée. Une vue peut souvent fonctionner sans contrôleur correspondant, mais un contrôleur est généralement beaucoup moins utile, sans vue. Les contrôleurs conviviaux utilisent la vue pour interpréter l'entrée de l'utilisateur de manière plus significative et intuitive. C'est ce qui rend difficile la séparation du concept de contrôleur de la vue.

Pensez à un robot radiocommandé sur un champ de détection dans une boîte scellée comme modèle.

Le modèle concerne les transitions d'état et d'état sans concept de sortie (affichage) ou de ce qui déclenche les transitions d'état. Je peux avoir le robot position sur le terrain et le robot sait comment faire la transition de position (faire un pas en avant/arrière/gauche/droite. Facile à imaginer sans vue ni contrôleur, mais ne fait rien d'utile

Pensez à une vue sans contrôleur, par exemple quelqu'un dans une autre pièce du réseau dans une autre pièce regardant la position du robot comme coordonnées (x,y) en streaming vers le bas d'une console de défilement. Cette vue affiche simplement l'état du modèle, mais ce type n'a pas de contrôleur. Encore une fois, facile à envisager cette vue sans contrôleur.

Pensez à un contrôleur sans vue, par exemple quelqu'un enfermé dans un placard avec le contrôleur radio réglé sur la fréquence du robot. Ce contrôleur envoie une entrée et provoque des transitions d'état sans aucune idée de ce qu'ils font au modèle (le cas échéant). Facile à imaginer, mais pas vraiment utile sans une sorte de retour de la vue.

L'interface utilisateur la plus conviviale coordonne la vue avec le contrôleur pour fournir une interface utilisateur plus intuitive. Pour exemple, imaginez une vue / contrôleur avec un écran tactile montrant la position actuelle du robot en 2D et permet à l'utilisateur de toucher le point de l'écran qui se trouve juste devant le robot. Le contrôleur a besoin de détails sur la vue, par exemple la position et l'échelle de la fenêtre, et la position de pixel du point touché par rapport à la position de pixel du robot sur l'écran) pour interpréter correctement (contrairement au gars enfermé dans le placard avec la radio contrôleur).

Ai-je déjà répondu à votre question? :-)

Le contrôleur est tout ce qui prend l'entrée de l'utilisateur qui est utilisé pour provoquer l'état de transition du modèle. Essayez de garder la vue et le contrôleur séparés, mais réalisez qu'ils sont souvent interdépendants l'un de l'autre, donc c'est correct si la frontière entre eux est floue, c'est-à-dire que la vue et le contrôleur en tant que paquets séparés peuvent ne pas être aussi proprement séparés que vous le souhaiteriez, mais c'est correct. Vous pourriez avoir à accepter l' le contrôleur ne sera pas séparé proprement de la vue car la vue est du modèle.

... est ce que toute validation etc doit être fait dans le Contrôleur? Si oui, comment faire I commentaires messages d'erreur retour à la View-cela devrait-il passer par le Modèle à nouveau, ou le contrôleur devrait-il il suffit de le renvoyer directement pour voir?

Si la validation est effectuée dans la vue, que dois-je mettre dans le Contrôleur?

Je dis qu'une vue liée et un contrôleur doivent interagir librement sans passer par le modèle. Le contrôleur prend l'entrée de l'utilisateur et doit effectuer la validation (peut-être en utilisant les informations du modèle et/ou de la vue), mais si la validation échoue, le contrôleur doit être en mesure de mettre à jour directement sa vue associée (par exemple, message d'erreur).

Le test acide pour cela est de vous demander si une vue indépendante (c'est-à-dire le gars dans l'autre pièce regardant la position du robot via le réseau) devrait voir quoi que ce soit ou non à la suite de quelqu'un d'autre erreur de validation (par exemple, le gars dans le placard a essayé de dire au robot de quitter le terrain). Généralement, la réponse est non - l'erreur de validation a empêché la transition d'état. S'il n'y avait pas de tranistion d'état (le robot n'a pas bougé), il n'est pas nécessaire de dire aux autres vues. Le gars dans le placard n'a tout simplement pas reçu de commentaires indiquant qu'il avait essayé de provoquer une transition illégale (pas d'interface utilisateur mal vue), et personne d'autre n'a besoin de le savoir.

Si le gars avec l'écran tactile a essayé de envoyez le robot hors du terrain, il a reçu un joli message convivial lui demandant de ne pas tuer le robot en l'envoyant hors du champ de détection, mais encore une fois, personne d'autre n'a besoin de le savoir.

Si d'autres vues fontbesoin de connaître ces erreurs, alors vous dites effectivement que les entrées de l'utilisateur et les erreurs résultantes font partie du modèle et le tout est un peu plus compliqué ...

 57
Author: Bert F, 2010-04-17 14:19:23

Voici un bon article sur les bases de la MVC.

Il indique ...

Controller-Le controller traduit interactions avec la vue en actions à effectuer par le modèle.

En d'autres termes, votre logique métier. Le contrôleur répond aux actions de l'utilisateur effectuées dans la vue et répond. Vous mettez la validation ici et sélectionnez la vue appropriée si la validation échoue ou réussit (page d'erreur, boîte de message, quoi).

Il y a un autre bon article chez Fowler.

 23
Author: JP Alioto, 2017-09-14 15:47:47

Le modèle MVC veut simplement que vous sépariez la présentation (=view) de la logique buisiness (=model). La partie contrôleur n'est là que pour semer la confusion.

 14
Author: Dimitri C., 2009-11-23 09:23:56

Sur la base de votre question, j'ai l'impression que vous êtes un peu flou sur le rôle du modèle. Le Modèle est fixé sur les données associées à l'application; si l'application dispose d'une base de données, le Modèle de l'emploi sera de parler. Il gérera également toute logique simple associée à ces données; si vous avez une règle qui dit que pour tous les cas où TABLE.foo = = " Hourra!"et de la TABLE.bar = = " Huzzah!"puis la TABLE de jeu.champ= " W00t!", alors vous voulez que le modèle s'en occupe.

Le Le contrôleur est ce qui devrait gérer la majeure partie du comportement de l'application. Donc, pour répondre à vos questions:

" Est-ce que je mets le public void actionPerformed(ActionEvent e) dans la vue avec juste un appel à une méthode dans le contrôleur?"

Je dirais non. Je dirais que cela devrait vivre dans le Contrôleur; la Vue devrait simplement alimenter les données provenant de l'interface utilisateur dans le Contrôleur, et laisser le contrôleur décider quelles méthodes doivent être appelées en réponse.

" Si oui, devrait toute validation etc être fait dans le contrôleur?"

La majeure partie de votre validation devrait vraiment être effectuée par le contrôleur; il devrait répondre à la question de savoir si les données sont valides ou non, et si ce n'est pas le cas, alimenter les messages d'erreur appropriés à la vue. En pratique, vous pouvez incorporer quelques vérifications de santé mentale simples dans la couche de vue afin d'améliorer l'expérience utilisateur. (Je pense principalement aux environnements Web, où vous voudrez peut-être qu'un message d'erreur apparaisse le moment venu l'utilisateur clique sur "Soumettre" plutôt que d'attendre tout le cycle de page soumettre -> processus -> charger avant de leur dire qu'ils ont foiré.) Faites attention; vous ne voulez pas dupliquer l'effort plus que vous ne le devez, et dans beaucoup d'environnements (encore une fois, je pense au Web), vous devez souvent traiter toutes les données provenant de l'interface utilisateur comme un paquet de mensonges sales et sales jusqu'à ce que vous ayez confirmé qu'il est réellement légitime.

" Si oui, comment puis-je renvoyer les messages d'erreur à la Vue-si cela parcourez à nouveau le modèle, ou le contrôleur devrait-il simplement le renvoyer directement à View?"

Vous devriez avoir un protocole configuré où la Vue ne sait pas nécessairement ce qui se passe ensuite jusqu'à ce que le contrôleur le dise. Quel écran leur montrez-vous après que l'utilisateur ait frappé ce bouton? La Vue peut ne pas savoir, et le contrôleur peut ne pas savoir non plus jusqu'à ce qu'il regarde les données qu'il vient d'obtenir. Il peut s'agir de "Aller à cet autre écran, comme prévu" ou "Rester sur cet écran et afficher cette erreur message".

D'après mon expérience, la communication directe entre le Modèle et la Vue devrait être très, très limitée, et la Vue ne devrait pas modifier directement les données du Modèle; cela devrait être le travail du Contrôleur.

" Si la validation est effectuée dans la vue, que dois-je mettre dans le contrôleur?"

Voir ci-dessus; la validation réelle doit être dans le contrôleur. Et j'espère que vous avez une idée de ce qui devrait être mis dans le contrôleur maintenant. :-)

, Il est intéressant de noter que tout peut devenir un peu flou sur les bords; comme avec la plupart des choses aussi complexes que le génie logiciel, les appels de jugement abonderont. Utilisez simplement votre meilleur jugement, essayez de rester cohérent dans cette application et essayez d'appliquer les leçons que vous apprenez au prochain projet.

 9
Author: BlairHippo, 2009-06-19 00:44:53

Pratiquement parlant, je n'ai jamais trouvé le concept de contrôleur particulièrement utile. J'utilise une séparation stricte modèle/vue dans mon code mais il n'y a pas de contrôleur clairement défini. Cela semble être une abstraction inutile.

Personnellement, MVC à part entière semble être le modèle de conception d'usine en ce sens qu'il conduit facilement à une conception confuse et trop compliquée. Ne soyez pas un astronaute d'architecture .

 9
Author: John Kugelman, 2017-05-23 10:31:26

Le contrôleur fait vraiment partie de la vue. Son travail consiste à déterminer quels services sont nécessaires pour répondre à la demande, à décompresser les valeurs de la Vue dans les objets requis par l'interface de service, à déterminer la vue suivante et à rassembler la réponse dans un formulaire que la vue suivante peut utiliser. Il gère également toutes les exceptions qui sont levées et les rend dans des vues que les utilisateurs peuvent comprendre.

La couche de service est la chose qui connaît les cas d'utilisation, les unités de travail et le modèle objet. Le contrôleur sera différent pour chaque type de vue - vous n'aurez pas le même contrôleur pour les interfaces utilisateur de bureau, basées sur un navigateur, Flexibles ou mobiles. Donc, je dis que cela fait vraiment partie de l'interface utilisateur.

Orienté service: c'est là que le travail est fait.

 7
Author: duffymo, 2009-06-19 01:16:54

Le contrôleur sert principalement à la coordination entre la vue et le modèle.

Malheureusement, il finit parfois par être mélangé avec la vue - dans de petites applications, bien que ce ne soit pas trop mal.

Je vous suggère de mettre le:

public void actionPerformed(ActionEvent e)

Dans le contrôleur. Ensuite, votre écouteur d'action dans votre vue doit déléguer au contrôleur.

Quant à la partie validation, vous pouvez la mettre dans la vue ou le contrôleur, je pense personnellement qu'elle appartient à la contrôleur.

Je recommanderais certainement de jeter un coup d'œil à la vue passive et au présentateur de supervision (qui est essentiellement ce que Model View Presenter est divisé en - au moins par Fowler). Voir:

Http://www.martinfowler.com/eaaDev/PassiveScreen.html

Http://www.martinfowler.com/eaaDev/SupervisingPresenter.html

 3
Author: Jon, 2009-06-19 00:40:21

Voici une règle de base que j'utilise: si c'est une procédure que je vais être à l'aide de spécifiquement pour une action sur ce page, il appartient au contrôleur, pas le modèle. Le modèle ne devrait fournir qu'une abstraction cohérente au stockage des données.

J'ai trouvé cela après avoir travaillé avec une webapp de grande taille écrite par des développeurs qui pensaient qu'ils étaient compris MVC mais ne l'ont vraiment pas fait. Leurs "contrôleurs" sont réduits à huit lignes d'appel de méthodes de classe statiques qui sont généralement appelés nulle part ailleurs :-/ rendant leurs modèles un peu plus que des moyens de créer des espaces de noms. Refactoring cela fait correctement trois choses: déplace tout le SQL dans la couche d'accès aux données (aka model), rend le code du contrôleur un peu plus verbeux mais beaucoup plus compréhensible, et réduit les anciens fichiers "modèle" à rien. :-)

 3
Author: staticsan, 2009-06-19 01:02:49

Notez également que chaque widget Swing peut être considéré comme contenant les trois composants MVC: chacun a un Modèle (ie ButtonModel), une Vue (BasicButtonUI) et un Contrôle (JButton lui-même).

 1
Author: akf, 2009-06-19 01:00:47

Vous avez essentiellement raison sur ce que vous mettez dans le contrôleur. C'est le seul moyen pour le Modèle d'interagir avec la Vue. L'actionperformed peut être placé dans la vue, mais la fonctionnalité réelle peut être placée dans une autre classe qui agirait en tant que contrôleur. Si vous allez faire cela, je recommande de regarder dans le modèle de commande, qui est un moyen d'abstraire toutes les commandes qui ont le même récepteur. Désolé pour la digression.

De toute façon, un MVC approprié la mise en œuvre aura les interactions suivantes uniquement: Modèle -> Voir Affichage -> Contrôleur Contrôleur - > Vue

Le seul endroit où il peut y avoir une autre interaction est que si vous utilisez un observateur pour mettre à jour la Vue, la Vue devra demander au Contrôleur les informations dont elle a besoin.

 1
Author: mnuzzo, 2009-06-19 01:12:32

Si je comprends bien, le contrôleur traduit des actions de l'interface utilisateur aux actions au niveau de l'application. Par exemple, dans un jeu vidéo, le contrôleur peut traduire "déplacé la souris tant de pixels" en "veut regarder dans telle ou telle direction. Dans une application CRUD, la traduction pourrait être "cliqué sur tel ou tel bouton" imprimer cette chose", mais le concept est le même.

 0
Author: David Seiler, 2009-06-19 00:05:20

Nous le faisons ainsi, en utilisant des contrôleurs principalement pour gérer et réagir aux entrées/actions pilotées par l'utilisateur (et _Logic pour tout le reste, sauf la vue, les données et les éléments _Model évidents):

(1) (réponse, réaction-ce que la webapp "fait" en réponse à l'utilisateur) Blog_Controller

- > main ()

Vous pouvez utiliser la fonction handleSubmit_AddNewCustomer ()

- > verifyUser_HasProperAuth ()

(2) ("business" logique, quoi et comment la webapp "penser") Blog_Logic

->sanityCheck_AddNewCustomer()

- > handleUsernameChange ()

->sendEmail_NotifyRequestedUpdate()

(3) (vues, portails, comment la webapp "apparaît") Blog_View

->genWelcome()

Vous pouvez utiliser la fonction genForm_AddNewBlogEntry()->genForm_AddNewBlogEntry ()]} Vous pouvez utiliser la fonction genPage_DataEntryForm()->genPage_DataEntryForm ()]}

(4) (objet de données uniquement, acquis dans _construct() de chaque classe Blog*, utilisé pour conserver toutes les données webapp/inmemory en un seul objet) Blog_Meta

(5) (couche de données de base, lit / écrit sur DBs) Blog_modèle

->saveDataToMemcache()

->saveDataToMongo()

Vous pouvez utiliser la fonction saveDataToSql ().]} Vous pouvez utiliser la fonction loadData()

->loadData ()

Parfois, nous sommes un peu confus sur l'endroit où mettre une méthode, dans le C ou le L. Mais le modèle est solide comme le roc, limpide, et puisque toutes les données en mémoire résident dans le _Meta, c'est une évidence là aussi. Notre plus grand bond en avant a été d'adopter l'utilisation _Meta, soit dit en passant, car cela a effacé tout le crud du divers objets _C, _L et _Model, ont rendu le tout mentalement facile à gérer, en plus, d'un seul coup, cela nous a donné ce qu'on appelle "l'injection de dépendance", ou un moyen de passer autour d'un environnement entier avec toutes les données (dont le bonus est la création facile d'un environnement de "test").

 0
Author: FYA, 2011-05-20 16:22:49