Dans une architecture MVC, dans quelle mesure le modèle et la vue sont-ils étroitement liés au contrôleur?

16

J'ai une application qui utilise MVC, mais je me bats un peu sur la façon dont le contrôleur doit être architecturé. Par exemple, la vue affiche uniquement un sous-ensemble des données du modèle à la fois. Cependant, je ne sais pas exactement comment cela devrait être organisé. Est-il normal que la vue ou le modèle appelle directement des fonctions sur le contrôleur, par exemple? Par une sorte d'interface? Ou sont-ils totalement encapsulés et ne connaissent jamais le contrôleur ou l'autre?

Tout comme un montage; il s'agit d'une application personnalisée qui n'est écrite dans aucun cadre Web, donc je ne recherche pas de détails spécifiques au cadre ici et j'ai la liberté de faire mon propre choix.

DeadMG
la source
1
Je ne répondrai pas parce que mon expérience est limitée dans les architectures MVC, mais d'après tout ce que j'ai entendu et parlé aux autres, les M&V sont étroitement couplés les uns aux autres mais pas au C. Le M appelle généralement des fonctions sur le C et le V ne lie souvent que des données à un sous-ensemble du M.
Steven Evers
8
@SnOrfus: C'est exactement l'opposé de ce que je pensais - les M&V sont couplés au C mais pas les uns aux autres.
DeadMG
1
Comment tant de réponses peuvent-elles être si fausses. Lisez ici la version MS msdn.microsoft.com/en-us/library/ff649643.aspx
Reactgular
Lisez cet article: objectmentor.com/resources/articles/taskmast.pdf
Edward Strange

Réponses:

15

Le contrôleur contrôle le flux d'activité. L'utilisateur effectue cette action, le contrôleur transmet les données de vue au domaine qui fait tout ce qu'il doit faire ensuite, en fonction de la ou des réponses, le contrôleur indique au framework quelle vue afficher ensuite (et lui donne suffisamment de données à faire donc).

Le contrôleur doit donc être couplé au modèle de domaine, dans une certaine mesure. c'est à dire. Vous pouvez mettre une couche de service entre les deux mais, par définition stricte, cela fait partie du domaine.

Il est également couplé aux données de vue mais pas à la vue elle-même. c'est à dire. il dit simplement "afficher la vue du client en utilisant ce détail client". Le cadre décide ensuite où il doit trouver cette vue.

Maintenant, cela devrait vous permettre de dissocier le modèle de domaine de la vue, en utilisant un modèle de vue des mêmes données. Certains développeurs le font, d'autres non, et je pense que c'est en grande partie une question de préférence personnelle.

Dans Rails, vous êtes très encouragé à pousser les objets de domaine (ActiveRecord) vers la vue et à vous assurer que la vue ne profite pas de cet accès (par exemple, vous ne devriez pas appeler customer.save depuis la vue, même si elle serait disponible).

Dans le monde .NET, nous avons tendance à réduire les risques en n'autorisant pas les choses qui ne devraient pas se produire et, peut-être pour cette raison, il me semble que le modèle de vue détachée est plus populaire.

pdr
la source
1
Le modèle de vue est une pratique très courante en matière de tests unitaires. Vous devez normalement mapper automatiquement un modèle de domaine ou un objet DTO à un modèle de vue. Vous utiliseriez alors votre modèle de vue dans une vue. Le modèle de vue est facilement testable et n'est pas lié à un calque ci-dessous.
CodeART
7

Remarque: Robert C. Martin (alias Oncle Bob) explique cela d'une manière bien meilleure et humoristique dans son discours, Architecture the Lost Years . Un peu long mais enseigne plein de bons concepts.

tl; dr: Ne pensez pas et ne planifiez pas votre application en termes de MVC. Le framework MVC n'est qu'un détail d'implémentation.

La chose la plus déroutante à propos de MVC est que les développeurs essaient d'utiliser tous les composants collés ensemble.

Essayez de penser en termes de programme, pas en termes de cadre.

Votre programme a un but. Il prend des données, fait des choses avec les données et renvoie des données.

De cette façon, le controllerest le mécanisme de livraison de votre programme.

  1. Un utilisateur envoie une demande à votre programme (disons, ajoutez un produit au panier).
  2. Le contrôleur prend cette demande (informations produit et informations utilisateur), il appelle la partie nécessaire de votre programme qui traitera cette demande $user->addToCart($product)
  3. Votre programme ( addToCartfonction de l' userobjet dans ce cas) fait le travail auquel il est destiné et renvoie une réponse (disons success)
  4. Le contrôleur prépare la réponse en utilisant les éléments pertinents view: par exemple. dans l'objet contrôleur$this->render($cartView('success')

De cette façon, les contrôleurs sont découplés du programme et utilisés comme mécanisme de livraison. Ils ne savent pas comment fonctionne votre programme, ils savent simplement quelle partie du programme doit être appelée pour les demandes.

Si vous souhaitez utiliser un autre framework, votre application n'aura pas besoin de changement, il vous suffira d'écrire les contrôleurs appropriés pour appeler votre programme pour les demandes.

Ou si vous souhaitez créer une version de bureau, votre application restera la même, il vous suffira de préparer un mécanisme de livraison.

Et le Model . Considérez-le comme un mécanisme de persistance.

De la manière OO, il existe des objets dans votre programme qui contiennent les données.

class User {
    //...
    private $id;
    private $shoppingCart;
    //...
}

class Product {
    //...
    private $id;
    //...
}

Lorsque vous ajoutez un produit au panier, vous pouvez ajouter le product::idau auuser::shoppingCart .

Et lorsque vous souhaitez conserver les données, vous pouvez utiliser le model partie du framework, qui consiste généralement à utiliser un ORM, pour mapper les classes aux tables de la base de données.

Si vous souhaitez modifier l'ORM que vous utilisez, votre programme restera le même, seules les informations de mappage changeront. Ou si vous voulez éviter les bases de données toutes ensemble, vous pouvez simplement écrire les données dans des fichiers en texte brut et votre application restera la même.


Alors, écrivez d'abord votre programme. Si vous programmez avec la méthode 'OO', utilisez de simples objets anciens du langage. Ne pensez pas en termes de MVC au premier abord.

Hakan Deryal
la source
Bonne vidéo. Merci. Je ne suis cependant pas d'accord avec votre interprétation. MVC n'est pas un détail dans le sens que l'oncle Bob y a. Vous remarquerez que MVC est un modèle architectural tout comme son modèle "Interactor / Entity / Boundary" qu'il établit. D'un autre côté, tout système MVC particulier, comme Spring ou autre, est en effet quelque chose qu'il recommande de différer. Comme il l'explique cependant, ces cadres appelés "MVC" sont en quelque sorte une bâtardise du terme.
Edward Strange,
Oui, j'ai écrit cela de la façon dont les gens pensent ce qu'est un MVC. C'est pourquoi j'ai écrit MVC Framework.
Hakan Deryal
2

Martin Fowler décrit bien le paradigme MVC. Voici un lien vers son article à ce sujet http://martinfowler.com/eaaDev/uiArchs.html

Notez sa citation sur la présentation séparée "L'idée derrière la présentation séparée est de faire une distinction claire entre les objets de domaine qui modélisent notre perception du monde réel, et les objets de présentation qui sont les éléments d'interface graphique que nous voyons à l'écran."

Johnnie
la source
1

Voici un exemple simple de la façon dont MVC peut être utilisé dans une application Java Swing typique ...

Disons que vous avez un panneau contenant un bouton et un champ de texte. Lorsque le bouton est enfoncé, un événement est déclenché, ce qui entraîne un changement d'état dans l'application. Une fois le changement d'état enregistré, le TextField devient désactivé.

Ce serait donc l'approche typique adoptée par une simple application MVC ...

Le contrôleur s'enregistre en tant qu'écouteur des événements de la vue. Lorsque le bouton est cliqué, la vue elle-même ne gère pas l'événement; le contrôleur le fait. Le contrôleur est spécifique à Swing car il doit gérer les événements liés à Swing.

Le contrôleur reçoit cette notification et doit décider qui doit la gérer (la vue ou le modèle). Étant donné que cet événement changera l'état de l'application, il décide de transmettre les informations au modèle qui est responsable des données et de la logique du programme. Certains font l'erreur de placer la logique du programme dans le contrôleur, mais dans la POO, les modèles représentent à la fois les données ET le comportement. Lisez Martin Fowler sur son point de vue.

Le message est reçu par le modèle dans le contexte approprié. Autrement dit, il est complètement vide de toute référence à Swing ou à toute autre référence spécifique à l'interface graphique. Ce message s'adresse au modèle et UNIQUEMENT au modèle. Si vous vous trouvez à importer des instructions javax.swing dans le modèle, vous ne codez pas correctement le modèle.

Le modèle définit ensuite son état sur «désactivé» et procède à la notification aux parties intéressées de ce changement de modèle. The View, intéressé par cet événement, s'est déjà inscrit en tant qu'observateur de tout changement de modèle. Une fois que l'événement de changement d'état du modèle est détecté par la vue, il procède à la désactivation de son TextField. Il est également légal pour la vue d'obtenir des informations en lecture seule directement à partir de son modèle sans avoir à passer par le contrôleur (généralement via une interface spécifique exposée par le modèle pour une telle activité).

En favorisant un tel couplage lâche entre la présentation et la logique métier et les couches de données, vous constaterez que votre code est beaucoup plus facile à gérer. À mesure que les systèmes grandissent, votre approche de MVC augmentera également. Par exemple, Hierarchical MVC est une extension souvent utilisée pour relier les triades MVC ensemble pour former de grands systèmes à l'échelle de l'entreprise sans coupler les sous-systèmes ensemble

Constantin
la source
0

Le couplage (le type que vous souhaitez éviter) implique une dépendance mutuelle entre deux classes. Autrement dit, un Foo dépend d'une barre et une barre dépend d'un foo de sorte que vous ne pouvez pas vraiment modifier l'un sans modifier l'autre. C'est une mauvaise chose.

Cependant, vous ne pouvez pas vraiment éviter d'avoir QUELQUES dépendances. Les classes doivent se connaître un peu, sinon elles ne communiqueraient jamais.

Dans le modèle MVC, le contrôleur contrôle la communication entre le modèle de domaine et la vue de présentation. En tant que tel, le contrôleur doit en savoir suffisamment sur le modèle pour lui demander de faire ce qu'il est censé faire. Le contrôleur doit également connaître suffisamment la vue pour pouvoir la présenter au client ou aux utilisateurs. Ainsi, le contrôleur de modèle a des dépendances sur les deux. Cependant, la vue peut parfaitement exister sans le contrôleur - il n'y a aucune dépendance là-bas. De même, le modèle n'a pas de dépendances sur le contrôleur - c'est simplement ce qu'il est. Enfin, le modèle et la vue sont complètement séparés l'un de l'autre.

Essentiellement, le contrôleur est le niveau d'indirection qui dissocie la vue du modèle, afin qu'ils n'aient pas à se connaître.

Matthew Flynn
la source
Ah - c'est pourquoi les downvotes - j'ai mal écrit. Je voulais dire que le contrôleur a des dépendances sur les deux. Oh!
Matthew Flynn
-5

D'après mon expérience, le modèle ne dépend généralement que d' un vue, et non d'une vue spécifique, souvent en tant qu'observateur ... s'il possède un tel couplage.

La vue se couple généralement à tout ce qu'elle regarde, ce qui est logique. Difficile de trouver une vue qui pourrait être découplée de ce qu'elle regarde ... mais parfois vous pouvez avoir un couplage partiel ou quelque chose.

Le contrôleur a souvent tendance à se coupler aux deux. Cela a également un certain sens, car il est de transformer les événements d'affichage en changements de modèle.

Bien sûr, ce n'est qu'une tendance que j'ai observée et ne dit vraiment rien sur un exemple spécifique.

Pour comprendre ce qu'est MVC et ce que la relation de couplage a tendance à être, vous devriez voir comment MVC est devenu. L'environnement dans lequel MVC a été créé était un environnement dans lequel les "widgets" en tant qu'éléments de formulaire avec lesquels vous pouvez créer des dialogues n'existaient pas. Une "vue" était une boîte et elle dessinait des trucs. Une vue de texte serait une boîte qui dessinerait du texte. Une vue de liste était une boîte qui dessinait une liste. Le "contrôleur" a reçu tous les événements de souris et de clavier du système d'interface utilisateur qui ont eu lieu dans cette vue; il n'y a eu aucun événement "textChanged" ou "selectionChanged". Le contrôleur prendrait tous ces événements de bas niveau et générerait une interaction avec le modèle. Le modèle, une fois modifié, ferait part de ses vues; nous sommes depuis venus pour voir cette relation comme "observateur" et il '

C'EST l'essence du modèle MVC. Étant donné que ce type de programmation d'interface utilisateur de bas niveau n'est généralement plus effectué, le MVC a évolué dans de nombreuses directions différentes. Certaines choses qui portent ce nom aujourd'hui ne ressemblent presque pas du tout au MVC et devraient vraiment s'appeler autre chose. Il peut toujours être utilisé dans le sens d'une boîte de dialogue dans son ensemble interagissant avec un objet plus grand. Il existe cependant de bien meilleures alternatives.

Fondamentalement, tout ce que le MVC devait résoudre se produit maintenant à l'intérieur des widgets et nous ne devons plus l'utiliser.


Pour ceux qui pensent savoir mieux:

http://www.codeproject.com/Articles/42830/Model-View-Controller-Model-View-Presenter-and-Mod

http://msdn.microsoft.com/en-us/library/ff649643.aspx

Je suis sûr qu'il y en a plus, mais ce ne sont que le haut de la liste dans google. Comme vous pouvez le voir, le modèle dépend beaucoup d'une interface de vue dans de nombreuses implémentations. Généralement, un modèle est observable et la vue est un observateur.

Mais pourquoi laisser les faits gêner ...

Un article déjà publié dans une autre réponse corrobore également mes affirmations:

http://martinfowler.com/eaaDev/uiArchs.html

Si les gens veulent continuer à dire que TOUT LE MONDE dans l'industrie du design a tort, c'est bien.

Edward Strange
la source
4
C'est tout à fait faux. Un modèle ne doit jamais dépendre d'une vue! Même si cette vue est abstraite ou une interface. Un modèle doit être totalement découplé de la présentation!
Falcon
3
La réponse est fausse. Le modèle ne dépend pas d'une vue ou d'un contrôleur.
CodeART
2
@Crazy Eddie Vous avez dit: "D'après mon expérience, le modèle ne dépend généralement que d'une vue, pas d'une vue spécifique, souvent en tant qu'observateur". Votre référence citée dit: "Cependant, le modèle ne dépend ni de la vue ni du contrôleur." Avez-vous même lu l'article cité? Ça ne ressemble pas à ça.
CodeART
2
@ Crazy Eddie: Je me fiche de ce que quelqu'un écrit sur un projet de code merdique. Ceci est une conception horrible. Utiliser un observateur pour écouter les changements est correct, mais mettre une interface de présentation dans un modèle de domaine est tellement faux. Le code cité de l'article est défectueux à certains égards fondamentaux en ce qui concerne MVC. Il laisse même le modèle dépendre implicitement du contrôleur. Quelle merde.
Falcon
3
@Crazy Eddie: lol @ downvote rampage. Je t'ai enragé?
Falcon
-7
  • Le contrôleur distribue le modèle à une vue et il traite le modèle soumis à partir des vues, mais il n'est pas étroitement couplé à une vue ou à un modèle.

Si le contrôleur était étroitement couplé à une vue, nous serons alors dans un monde de formulaires Web. Vous auriez un code derrière lequel serait lié à un fichier de modèle (applicable aux formulaires Web ASP.NET)

Pour cette raison, le contrôleur n'est pas couplé à un modèle ou à une vue. C'est juste un mécanisme pour traiter les demandes et envoyer des réponses.

  • La vue est étroitement couplée à un modèle. Apportez des modifications à votre modèle (par exemple, modifiez sa propriété) et vous devrez apporter des modifications à votre vue.

  • Le modèle n'est pas étroitement couplé à une vue. Apportez des modifications à une vue et cela n'aura aucun effet sur un modèle.

  • Le modèle ne sait rien du contrôleur ni des vues où il peut être utilisé. Par conséquent, le modèle n'est pas étroitement couplé à une vue ou à un contrôleur.

Une autre façon de penser à cela:

  • Apportez des modifications à un contrôleur - la vue et le modèle ne seront pas affectés

  • Apportez des modifications à un modèle - la vue sera interrompue car elle dépend d'un modèle

  • Apportez des modifications à une vue - le modèle et le contrôleur ne seront pas affectés

Ce couplage lâche dans les projets MVC est ce qui les rend faciles à tester unitaire.

CodeART
la source
1
C'est tellement faux que ce n'est pas drôle. Pas même la peine d'expliquer. Ignorez complètement cette réponse.
Reactgular
1
@MathewFoscarini Arrêtez de pleurer et laissez une "bonne réponse"
CodeART
2
lol, toute la théorie de conception derrière MVC est qu'ils ne dépendent pas les uns des autres.
Reactgular
J'ai laissé plus d'informations pour vous, j'espère que cela aura du sens
CodeART