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.