Architecture MVC - De combien de contrôleurs ai-je besoin?

54

Je code depuis un moment, mais principalement des scripts et des applications simples. J'ai changé de rôle et je me suis donné pour mission de développer des applications Web et d'utiliser une architecture MVC appropriée. J'essaie donc désespérément de découvrir tout cela très rapidement.

J'espère que cette question ne ressemble pas trop aux " Meilleures pratiques pour l'architecture MVC ", mais alors que je suis en train de parcourir quelques tutoriels différents, j'ai remarqué que certains avaient plusieurs contrôleurs pour différentes choses.

De combien de contrôleurs une seule application Web a-t-elle besoin?

Je me rends compte que ce serait difficile de répondre sans exemple, alors je vais vous en donner un:

Application:

  1. L'utilisateur se connecte.
  2. L'utilisateur peut faire l'une des trois choses suivantes:
    a) Télécharger un fichier (stocké dans une base de données mongodb avec des métadonnées).
    b) Recherchez un fichier.
    c) Déconnectez-vous.

Ma question est d'ordre général, mais j'ai donné l'exemple pour aider ceux qui essaient de répondre.

Jeff
la source
8
Une question vraiment bien posée.
Daniel Hollinrake

Réponses:

34

Pour votre exemple, je créerais deux contrôleurs:

  • Contrôleur de sessions pour la connexion et la déconnexion (créer et détruire une session pour REST comme une présentation)
  • Contrôleur de fichiers pour tout ce qui est sur les fichiers (index = rechercher et créer = télécharger)

En général, une approche RESTful dans laquelle vous pensez à tout comme une ressource pouvant être affichée, créée, modifiée et détruite vous donne une bonne idée de la structure à adopter. Comme vous pouvez le constater à partir de mes exemples, je ne colle pas trop près de chaque verbe dans REST.

Vous aurez probablement besoin de plus de contrôleurs pour plus de fonctionnalités. Par exemple, un contrôleur d'utilisateurs où les utilisateurs peuvent créer de nouveaux comptes. Et en plus de cela, vous aurez besoin d'une interface d'administration où vous pouvez éditer les ressources avec des privilèges plus élevés. Dans un tel cas, il est assez courant de faire dupliquer presque tous les contrôleurs.

Une idée très approximative pour avoir une idée initiale pourrait être un contrôleur pour chaque table de votre base de données accessible aux utilisateurs. Mais ce n’est vraiment qu’une mesure très grossière.

Thorsten Müller
la source
3
Prenons l'exemple de votre administrateur: le contrôleur administratif étendrait-il l'utilisateur général ou redéfiniriez-vous complètement toutes les méthodes? Par exemple, tous les utilisateurs peuvent peut-être télécharger et rechercher, mais seuls les administrateurs peuvent les supprimer. La classe de contrôleur d'administration hériterait-elle de toutes les méthodes utilisateur générales?
Jeff
4
Cela dépend vraiment beaucoup de la fonctionnalité réelle. Mais en général, j’écris simplement un deuxième contrôleur sans aucun héritage. Suivant le principe du «contrôleur léger», il ne devrait pas y avoir beaucoup de code dans un contrôleur. Et le contrôleur d'administration peut être particulièrement simple. Toutes les fonctionnalités importantes vont dans le modèle. (Par exemple, si la suppression d'un utilisateur signifie que tous ses fichiers doivent également être supprimés, alors le modèle le gère, il n'y a pas une seule ligne pour cela dans le contrôleur)
Thorsten Müller
6

Cela dépend vraiment de l'application Web. Dans votre exemple, un suffit probablement. Si vous deviez mettre en œuvre une application de commerce électronique complète avec expédition, taxes, gestion des stocks, tarification différenciée, etc., vous voudrez peut-être en avoir plusieurs autres.

Si votre contrôleur souffre d'une ou de plusieurs odeurs de code (en particulier de grande classe ou d'objet divin ), vous savez que vous avez probablement dépassé le point où vous n'en aurez plus qu'une.

Dan Pichelman
la source
5

Cela dépend vraiment des besoins de votre application et de l'architecture des modules métier.

En règle générale , le nombre de contrôleurs requis dépend d'un nombre de modules et de sous-modules dans l'application Web.

En complément, il serait utile d’organiser les contrôleurs en zones . Le concept de zones est intégré à l'infrastructure ASP.NET MVC et simplifie l'organisation des contrôleurs desservant un module.

Il y a un certain nombre de discussions connexes:

EL Yusubov
la source
1
Bonnes références! Je vais être sûr de les vérifier!
Jeff
Bien sûr pas de problème.
EL Yusubov
4

J'aime la façon dont Apple le fait.

Chaque vue est contrôlée par un seul contrôleur de vue. ~ Voir le Guide de programmation du contrôleur pour iOS

L'idée est que vous devriez pouvoir échanger facilement des vues. OMI, en ayant seulement 1 Controllerpar Viewil le rend plus facile à accomplir. Mais je suis sûr que vous pourriez avoir un contrôleur avec plusieurs vues et le concevoir de manière à pouvoir changer de vue sans changer la logique du programme.

Korey Hinton
la source
C'est un bon point, mais auriez-vous besoin d'un contrôleur pour chaque vue, ainsi que de plusieurs autres pour prendre en charge des tâches telles que les utilisateurs? Je suppose aussi que si mon projet était plus grand, il serait plus logique d’avoir plus de contrôleurs.
Jeff
Les modèles doivent garder une trace des utilisateurs. Ainsi, plusieurs contrôleurs peuvent tous utiliser le même objet de modèle si nécessaire.
Korey Hinton
2
Donc, un contrôleur a un objet Model et un objet View. Le contrôleur demande des informations à l'objet Modèle (telles que les informations utilisateur), puis définit la vue en conséquence. Le modèle doit disposer de la plupart de la logique du programme, tandis que le contrôleur ne dispose que de la logique lui permettant de communiquer entre la vue et le modèle.
Korey Hinton
2
Un contrôleur par vue est une conception très limitée, car votre contrôleur ne pourrait pas afficher différents modèles de vues pour différents états du modèle.
EL Yusubov
1
@ ElYusubov Je peux voir en quoi cela pourrait être déroutant. Dans iOS, chaque vue ne comporte qu'un seul contrôleur de vue et chaque contrôleur de vue n'a qu'une seule vue active (et cette vue peut avoir des sous-vues), mais ce contrôleur de vue peut également contenir des références à un nombre quelconque de vues.
Korey Hinton
2

Un exemple que j'aime bien pense à un thermostat. Un thermostat est un excellent visuel pour visualiser le modèle MVC.


Sur un thermostat analogique plus ancien, vous pouvez imaginer des choses comme ceci:

View - Le lecteur de température, qui affiche la température actuelle.

Contrôleur - Le cadran, où vous modifiez la température

Modèle - Les pièces internes invoquées par le contrôleur qui entraînent un changement de température.


Vous devez toujours respecter les conceptions qui permettent un couplage lâche, limiter les modèles et leurs contrôleurs associés à une tâche unique , et utiliser autant de modules / contrôleurs que nécessaire . En fonction de la taille de votre application, vous pouvez avoir beaucoup moins de vues que les modèles et les contrôleurs. Ceci est à prévoir avec n'importe quelle application de grande taille. Une bonne programmation orientée objet est caractérisée par un couplage lâche, une encapsulation, un héritage et un polymorphisme. Toutes les langues ne prennent pas en charge le polymorphisme au même degré (fonction, méthode, surcharge de l'opérateur).

Si vous souhaitez mieux comprendre comment utiliser correctement l'architecture MVC, consultez le document GoF "Modèles de conception: éléments d'un logiciel réutilisable ..." qui utilise le code C ++ et SmallTalk, par exemple. Ce livre n'est pas l'alpha et l'oméga, mais c'est certainement un début!

Bonne chance!

Charles Addis
la source
1

Je suppose que votre exemple évoluera vers un système complexe.

Application:

L'utilisateur se connecte:

  • LoginController

Sa seule responsabilité est de gérer les connexions, de rediriger ou d’informer l’utilisateur du résultat.

Télécharger un fichier

  • UploadController

Je suppose ici que vous voulez télécharger n'importe quel type de fichier. Si, à une date ultérieure, vous décidez de télécharger des fichiers MP3 et PDF, vous disposez alors des bases UploadController, MP3UploadController et PDFUploadController.

Rechercher un fichier.

  • SearchFileController

Cela suffirait pour une exigence de base. Vous pouvez avoir plusieurs contrôleurs de recherche ultérieurement, en fonction de la complexité de la logique de recherche. La dernière chose que vous souhaitez avoir est un seul SearchController avec 20 méthodes d’action qui effectuent différentes recherches.

Se déconnecter.

-LogoutController .

On pourrait considérer cela comme une exagération, mais je ne le pense pas. Je pense que c'est propre et bien séparé.

Si je regardais cette structure de projet, je saurais instantanément ce qu'il fait et comment il est structuré. Pour aller un peu plus loin, je mettrais LoginControlleret LogoutControllerdans une zone séparée.

J'ai déjà développé quelque chose comme ça et ça a très bien fonctionné.

CodeART
la source
Merci pour la contribution! Vous avez un code de travail? rester coincé sur quelques petites choses.
Jeff
Quels problèmes rencontrez-vous?
CodeART
Je peux télécharger un sujet et une date (au format chaîne), mais je ne peux pas télécharger le fichier lui-même (voir stackoverflow.com/questions/18344614/… ).
Jeff
Je suis un développeur .NET. Désolé je ne peux pas vous aider.
CodeART
1

La plupart de votre code se passerait dans une couche métier, n'est-ce pas? Si tel est le cas, tout ce que vous faites réellement dans votre contrôleur renvoie les données à la vue.

Pas vraiment sûr si je suis fan de séparer les contrôleurs en sous-types. Bien que vous devriez maintenir une séparation des préoccupations, je pense que les sous-types vont un peu trop loin. Vous devez également faire attention lorsque des objets lourds sont initialisés dans le constructeur ou un contrôleur. Par exemple: dans votre exemple, vous voudriez qu'un objet lourd, utilisé uniquement pour la recherche / le téléchargement du fichier, soit publié lorsque l'utilisateur est sur la page de connexion.

Il est préférable d'avoir un contrôleur par unité logique, par exemple AccountController (connexion, enregistrement, déconnexion), FileController (recherche, téléchargement), etc.

harsha
la source
0

En général, vous pouvez dire que chaque modèle a ses propres contrôleurs et vues dédiées. En général, je veux dire que c’est la meilleure pratique.

Les aspects de l'application (tels que la gestion des utilisateurs) doivent être traduits en service d'application et doivent être appelés par le contrôleur lui-même ou pour encapsuler votre contrôleur (en utilisant des attributs qui rendent la fonctionnalité du contrôleur "visible" en fonction du rôle d'utilisateur de la requête, par exemple).

N'oubliez pas que tous les contrôleurs doivent en principe gérer les opérations CRUD sur le modèle et utiliser différentes vues pour différents filtres.

À mon avis, l'un des principaux avantages de MVC en tant que modèle est qu'il offre le meilleur moyen de lier des modèles et des vues.

À propos de l’exemple que vous avez ajouté: Je créerais 2 contrôleurs: un pour l’opération de connexion de tous les utilisateurs (enregistrement, connexion, déconnexion, etc.) et le second pour les opérations sur les fichiers (téléchargement et recherche). notez que le premier doit également être sauvegardé avec un aspect lié à la fonctionnalité de connexion et le second est un contrôleur ordinaire

Technologies Saturne
la source
sans une explication, cette réponse peut devenir inutile dans le cas où quelqu'un d'autre affiche une opinion contraire. Par exemple, si quelqu'un dépose une revendication du type "La gestion des rôles et autorisations des utilisateurs ne doit pas être gérée par le contrôleur" , comment cette réponse aiderait-elle le lecteur à choisir deux opinions opposées? Envisagez de le modifier pour le transformer en forme
gnat
1
@gnat J'accepte votre commentaire. Voir la réponse modifiée
Saturn Technologies