J'ai utilisé MVP et MVC dans le passé, et je préfère MVP car il contrôle le flux d'exécution tellement mieux à mon avis.
J'ai créé mon infrastructure (classes de banque de données / référentiel) et les utilise sans problème lors du codage en dur des exemples de données, alors maintenant je passe à l'interface graphique et prépare mon MVP.
Section A
J'ai vu MVP utiliser la vue comme point d'entrée, c'est-à-dire dans la méthode du constructeur de vues, il crée le présentateur, qui à son tour crée le modèle, câblant les événements selon les besoins.
J'ai également vu le présentateur comme le point d'entrée, où une vue, un modèle et un présentateur sont créés, ce présentateur reçoit ensuite une vue et un objet de modèle dans son constructeur pour câbler les événements.
Comme en 2, mais le modèle n'est pas transmis au présentateur. Au lieu de cela, le modèle est une classe statique où les méthodes sont appelées et les réponses retournées directement.
Section B
En termes de synchronisation de la vue et du modèle, j'ai vu.
Chaque fois qu'une valeur dans la vue change, c'est-à-dire un
TextChanged
événement en .Net / C #. Cela déclenche unDataChangedEvent
qui est transmis dans le modèle, pour le garder synchronisé à tout moment. Et lorsque le modèle change, c'est-à-dire un événement d'arrière-plan qu'il écoute, la vue est mise à jour via la même idée de lever aDataChangedEvent
. Lorsqu'un utilisateur souhaite valider des modifications,SaveEvent
il se déclenche, passant dans le modèle pour effectuer la sauvegarde. Dans ce cas, le modèle imite les données de la vue et traite les actions.Semblable à # b1, cependant, la vue n'est pas toujours synchronisée avec le modèle. Au lieu de cela, lorsque l'utilisateur souhaite valider les modifications, il
SaveEvent
est renvoyé et le présentateur saisit les derniers détails et les transmet au modèle. dans ce cas, le modèle ne connaît pas les données de vues tant qu'il n'est pas nécessaire de les utiliser, auquel cas tous les détails nécessaires lui sont transmis.
Section C
Affichage des objets métier dans la vue, c'est-à-dire un objet (MyClass) et non des données primitives (int, double)
La vue possède des champs de propriété pour toutes ses données qu'elle affichera en tant qu'objets domaine / métier. Tels que
view.Animals
expose uneIEnumerable<IAnimal>
propriété, même si la vue les traite en nœuds dans un TreeView. Ensuite, pour l'animal sélectionné, il exposeraitSelectedAnimal
commeIAnimal
propriété.La vue n'a aucune connaissance des objets de domaine, elle expose uniquement les propriétés des types d'objets inclus primitifs / framework (.Net / Java). Dans ce cas, le présentateur passera un objet adaptateur l'objet domaine, l'adaptateur traduira ensuite un objet métier donné dans les contrôles visibles sur la vue. Dans ce cas, l'adaptateur doit avoir accès aux commandes réelles de la vue, et pas seulement à n'importe quelle vue, il devient donc plus étroitement couplé.
Section D
Plusieurs vues utilisées pour créer un seul contrôle. c'est-à-dire que vous avez une vue complexe avec un modèle simple comme la sauvegarde d'objets de différents types. Vous pouvez avoir un système de menus sur le côté à chaque clic sur un élément, les commandes appropriées sont affichées.
Vous créez une vue énorme, qui contient tous les contrôles individuels qui sont exposés via l'interface des vues.
Vous avez plusieurs vues. Vous avez une vue pour le menu et un panneau vide. Cette vue crée les autres vues requises mais ne les affiche pas (visible = false), cette vue implémente également l'interface pour chaque vue qu'elle contient (c'est-à-dire les vues enfants) afin qu'elle puisse l'exposer à un présentateur. Le panneau vide est rempli d'autres vues (
Controls.Add(myview)
) et ((myview.visible = true
). Les événements déclenchés dans ces vues "enfants" sont gérés par la vue parent qui à son tour transmet l'événement au présentateur, et vice versa pour restituer les événements aux éléments enfants.Chaque vue, que ce soit le parent principal ou les vues enfant plus petites, est connectée à son propre présentateur et modèle. Vous pouvez littéralement simplement déposer un contrôle de vue dans un formulaire existant et il aura la fonctionnalité prête, il suffit de câbler un présentateur dans les coulisses.
Section E
Si tout a une interface, maintenant basé sur la façon dont le MVP est fait dans les exemples ci-dessus affectera cette réponse car ils pourraient ne pas être compatibles.
Tout a une interface, la vue, le présentateur et le modèle. Chacun d'eux a alors évidemment une mise en œuvre concrète. Même si vous n'avez qu'une seule vue, modèle et présentateur concret.
La vue et le modèle ont une interface. Cela permet aux vues et aux modèles de différer. Le présentateur crée / reçoit des objets de vue et de modèle et il sert simplement à passer des messages entre eux.
Seule la vue a une interface. Le modèle a des méthodes statiques et n'est pas créé, donc pas besoin d'interface. Si vous voulez un modèle différent, le présentateur appelle un ensemble différent de méthodes de classe statique. Étant statique, le modèle n'a aucun lien avec le présentateur.
Pensées personnelles
De toutes les différentes variations que j'ai présentées (la plupart que j'ai probablement utilisées sous une certaine forme), dont je suis sûr qu'il y en a plus. Je préfère A3 comme gardant la logique métier réutilisable en dehors de MVP, B2 pour moins de duplication de données et moins d'événements déclenchés. C1 pour ne pas ajouter dans une autre classe, bien sûr, il met une petite quantité de logique non testable dans une vue (comment un objet de domaine est visualisé) mais cela pourrait être revu par le code, ou simplement visualisé dans l'application. Si la logique était complexe, je serais d'accord avec une classe d'adaptateurs mais pas dans tous les cas. Pour la section D, je pense que D1 crée une vue qui est au moins trop grande pour un exemple de menu. J'ai déjà utilisé D2 et D3. Le problème avec D2 est que vous finissez par avoir à écrire beaucoup de code pour router les événements vers et depuis le présentateur vers la vue enfant correcte, et ce n'est pas compatible par glisser / déposer, chaque nouveau contrôle a besoin de plus de câblage pour supporter le présentateur unique. D3 est mon choix préféré, mais ajoute encore plus de classes en tant que présentateurs et modèles pour gérer la vue, même si la vue s'avère très simple ou n'a pas besoin d'être réutilisée. je pense qu'un mélange de D2 et D3 est mieux basé sur les circonstances. En ce qui concerne la section E, je pense que tout ce qui a une interface pourrait être exagéré. Je le fais déjà pour les objets de domaine / métier et je ne vois souvent aucun avantage dans la "conception" en le faisant, mais cela aide à se moquer des objets dans les tests. Personnellement, je verrais E2 comme une solution classique, bien que j'aie vu E3 utilisé dans 2 projets sur lesquels j'ai travaillé précédemment. je pense qu'un mélange de D2 et D3 est mieux basé sur les circonstances. En ce qui concerne la section E, je pense que tout ce qui a une interface pourrait être exagéré. Je le fais déjà pour les objets de domaine / métier et je ne vois souvent aucun avantage dans la "conception" en le faisant, mais cela aide à se moquer des objets dans les tests. Personnellement, je verrais E2 comme une solution classique, bien que j'aie vu E3 utilisé dans 2 projets sur lesquels j'ai travaillé précédemment. je pense qu'un mélange de D2 et D3 est mieux basé sur les circonstances. En ce qui concerne la section E, je pense que tout ce qui a une interface pourrait être exagéré. Je le fais déjà pour les objets de domaine / métier et je ne vois souvent aucun avantage dans la "conception" en le faisant, mais cela aide à se moquer des objets dans les tests. Personnellement, je verrais E2 comme une solution classique, bien que j'aie vu E3 utilisé dans 2 projets sur lesquels j'ai travaillé précédemment.
Question
Suis-je en train d'implémenter MVP correctement? Y a-t-il une bonne façon de procéder?
J'ai lu le travail de Martin Fowler qui a des variations, et je me souviens quand j'ai commencé à faire du MVC, j'ai compris le concept, mais je ne pouvais pas à l'origine déterminer où est le point d'entrée, tout a sa propre fonction mais ce qui contrôle et crée l'original ensemble d'objets MVC.
la source
Réponses:
Beaucoup de ce que vous présentez ici est très raisonnable et sain. Certains choix vont dépendre des spécificités de l'application et de celui qui "se sent" bien. Comme c'est le cas la plupart du temps, il n'y aura pas de bonne réponse. Certains choix auront un sens ici et ces choix pourraient être complètement faux pour la prochaine application et les circonstances. Sans connaître certaines des spécificités de l'application, je pense que vous êtes sur la bonne voie et avez pris des décisions judicieuses et réfléchies.
Pour moi, je pense que le présentateur devrait presque toujours être le point d'entrée. Avoir l'interface utilisateur comme point d'entrée met trop de logique dans l'interface utilisateur et enlève la possibilité de remplacer une nouvelle interface utilisateur sans grands changements de codage. Et c'est vraiment le travail du présentateur.
la source
Nous utilisons une forme modifiée de MVP sur notre application .NET 2.0 Winforms. Les deux pièces qui nous manquaient étaient un adaptateur modifié du WPF ViewModel et l'ajout d'une liaison de données. Notre modèle spécifique est MVPVM.
Nous câblons en tant que présentateur en premier dans presque tous les cas, à l'exception des commandes d'utilisateur personnalisées, qui sont câblées en vue d'abord pour la convivialité du concepteur. Nous utilisons l'injection de dépendances, les ViewModels générés par code, BDD pour les présentateurs et TDD / TED pour le modèle.
Les machines virtuelles ne sont qu'une masse massive et plate de propriétés qui augmentent PropertyChanged lorsqu'elles sont modifiées. Il était très facile de les générer par code (et les tests unitaires d'exercices associés). Nous les utilisons pour lire et écrire sur des contrôles interactifs et contrôler les états activés. Le ViewModel est couplé à la vue, car nous utilisons la liaison de données pour sacrément près de tout le reste.
La vue aura parfois des méthodes pour accomplir des choses que la machine virtuelle ne peut pas faire. Cela contrôle généralement la visibilité des éléments (WinForms peut être pointilleux à ce sujet) et les choses qui refusent d'être liées aux données. La vue expose toujours des événements comme "Connexion" ou "Redémarrage", avec les EventArgs appropriés pour agir sur les comportements des utilisateurs. À moins que nous n'ayons dû utiliser un hack comme "View.ShowLoginBox", la vue est complètement interchangeable tant qu'elle répond aux exigences générales de conception.
Il nous a fallu environ 6 à 8 mois pour définir ce modèle. Il a beaucoup de pièces, mais est très flexible et extrêmement puissant. Notre implémentation spécifique est très asynchrone et pilotée par les événements, ce qui peut être simplement un artefact d'autres exigences plutôt qu'un effet secondaire du comportement de conception. Par exemple, j'ai ajouté la synchronisation des threads à la classe de base dont nos machines virtuelles héritent (qui a simplement exposé une méthode OnPropertyChanged pour déclencher l'événement) - et pouf, nous pouvons maintenant avoir des présentateurs et des modèles multithreads.
la source
J'utilise une version de PureMvc qui a été modifiée pour .Net, puis étendue par moi-même.
J'étais habitué à PureMvc de l'utiliser dans des applications Flex. Il s'agit d'un cadre de type barebones, il est donc assez facile de l'adapter si vous souhaitez le personnaliser.
J'ai pris les libertés suivantes avec lui:
Dans PureMvc, vous pouvez utiliser une commande comme point d'entrée, une commande de démarrage typique configurerait le modèle dans la mesure du possible, puis créerait le MainForm, créerait et enregistrerait le médiateur pour et avec ce formulaire, puis ferait Application. Sur le formulaire.
Le médiateur du formulaire serait responsable de la mise en place de tous les sous-médiateurs, certains pouvant être automatisés en utilisant, encore une fois, des astuces de réflexion.
Le système que j'utilise est compatible par glisser / déposer, si je comprends votre sens. Le formulaire réel est entièrement créé dans VS, mais mon expérience ne concerne que les formulaires dotés de contrôles créés statiquement. Des choses comme des éléments de menu créés dynamiquement semblent réalisables avec un peu de réglage du médiateur pour ce menu ou sous-menu. Là où cela deviendrait poilu, c'est lorsque le médiateur n'avait aucun élément racine statique à accrocher et que vous vous êtes mis à créer des médiateurs «d'instance» dynamiques.
la source