Pourquoi éviter l'héritage de forme?

9

Je me souviens avoir appris VB4 et avoir fait glisser un bouton sur un formulaire, double-cliquer sur ce bouton et taper du code dans ce gestionnaire d'événements dont je venais juste d'être béni par magie. Venant de QBASIC, j'étais ravi du "V" dans "VB", le concepteur visuel était littéralement la meilleure chose depuis le pain tranché.

Bien sûr, vous pouvez faire tout cela par programmation, mais la magie du "V" était si attrayante que vous ne pouviez pas vous empêcher de faire glisser ce bouton. Nous avons été encouragés à emprunter cette voie.

Mais il y a quelques années, j'ai commencé à découvrir C # et le framework .net et j'ai été fasciné par la façon dont tout ce que je pensais savoir venait de disparaître. Il y a beaucoup de magie dans VB6 qui est complètement dévoilé dans .net: prenez les constructeurs et la InitializeComponentsméthode par exemple. Dans ce dernier, vous trouverez toutes les instances de contrôle que vous avez faites glisser depuis la boîte à outils, tous les événements que vous avez enregistrés et les propriétés que vous avez définies dans le concepteur.

Et ça va ... je suppose. C'est juste, j'ai l'impression de ne pas "posséder" ce qui se passe, ce code que je ne peux que modifier via le concepteur me dérange énormément. Chaque fois que vous copiez un bouton qui dit "Ok" d'un formulaire à un autre (parfois avec son frère "Annuler"), vous dupliquez en fait du code, et c'est un péché n'est-ce pas? SEC, ne vous répétez pas, dit le Pape .

Les religions et les écoles de pensée mises à part, en toute objectivité, ne devrions-nous pas plutôt dériver des formes des formes de base et laisser le bouton "Ok" (et tous ses amis) vivre sur la forme de base? Quelque chose comme un FormBasedont dérive un DialogFormBase; toutes les classes créées en un rien de temps ... en tapant du code. Les boutons sont créés en fonction de la façon dont la classe est instanciée (c'est-à-dire qu'un argument d'énumération constructeur détermine quels boutons doivent être créés), les contrôles sont disposés à l'intérieur d'un agencement de panneaux divisés et de panneaux de disposition de flux, injectés dans le formulaire commeContentqui s'intègre dans le panneau de contenu principal. N'est-ce pas ce que fait ASP.net avec les pages maîtres et les espaces réservés de contenu? Je dérivais un formulaire lorsque j'avais besoin d'une nouvelle "page maître", mais cette nouvelle "page maître" dérive toujours d'une classe de formulaire de base, de sorte que les visuels sont cohérents dans l'ensemble de l'application.

Pour moi, c'est beaucoup plus de réutilisation de code que tout ce que j'ai jamais fait avec le concepteur dans WinForms, et ce n'était même pas difficile, et le code n'est pas encombré avec une méthode de 200 lignes sur laquelle je n'ai aucun contrôle, je peux mettre des commentaires où j'aime, ils ne seront pas écrasés par un designer. Je suppose que c'est juste une question de modèles et d'architecture, c'est ce qui m'a amené à ce lien: le meilleur design pour les formulaires Windows qui partageront des fonctionnalités communes , où j'ai réalisé que j'étais sur place, sauf la réponse là-bas, suggère exactement ce que je suis faire, mais il est conseiller contre l' héritage de forme en raison de considérations de design. C'est la partie que je ne comprends pas .en raison de considérations de structure de code, en particulier en ce qui concerne l'héritage de forme et de contrôle, que je ne vois aucune raison d'éviter, sinon il casse le concepteur .

Nous ne pouvons pas tous être paresseux, alors quelle partie me manque-t-elle?

Mathieu Guindon
la source
Je ne comprends pas. Voulez-vous dire que nous ne devons pas utiliser de concepteurs visuels et écrire tout le code de l'interface graphique à la main?
Euphoric
Avant .NET, où était le code qui contrôlait tous les objets glissés sur le formulaire?
JeffO
1
@JeffO à en juger par le code hérité que j'ai traité, je dirais directement sur le formulaire, quelque part entre le SQL intégré ad hoc et la logique métier. Le fait est que WinForms est .net; donc si le concepteur fonctionne bien avec ce qui sent de nos jours comme "mauvais code" et "mauvaises habitudes de codage" et se casse réellement lorsque vous commencez à structurer les choses, je dis de laisser tomber le concepteur et de traiter les formulaires comme ils sont (classes!) .. . et en quoi le codage d'une couche d'interface utilisateur en C # est-il si différent du codage d'une couche d'interface utilisateur dans ExtJS, de toute façon? C'est "fastidieux" de faire ça dans WinForms parce que "hey regarde il y a un designer"? Le codage d'une interface utilisateur ExtJS est-il fastidieux?
Mathieu Guindon
Je vais citer un autre utilisateur: CodeCaster; Un gestionnaire d'événements est destiné à connecter l'interface graphique à votre logique métier. Si vous avez une zone de texte pour entrer le nom d'un utilisateur et un bouton Ajouter, cliquer sur le bouton Ajouter doit simplement appeler _userRepository.AddUser (UsernameTextbox.Text). Vous ne voulez pas de logique métier dans les gestionnaires d'événements. stackoverflow.com/questions/8048196/…
Pieter B
@Pieter ne met-il pas une dépendance DAL dans votre couche de présentation?
Mathieu Guindon

Réponses:

9

Je vais vous opposer à un paradigme différent: privilégier la composition à l'héritage.

Même lorsque vous commencez à écrire du code GUI à la main et utilisez l'héritage pour partager le comportement et les visuels entre les formulaires, vous rencontrerez le même problème que la conception POO normale. Disons que vous avez DialogForm, qui a des boutons OK / Annuler et GridForm, qui a une grille. Vous dérivez toutes les boîtes de dialogue de DialogForm et tous les formulaires avec Grid de GridForm. Et puis vous découvrez que vous voulez vous mettre en forme avec les deux. Comment le résoudriez-vous? Si vous utilisez l'héritage de formulaire, il n'y a aucun moyen de le résoudre. De l'autre côté, si vous utilisez UserControls, vous pouvez simplement mettre GridControl sur votre formulaire et en finir avec lui. Et vous pouvez toujours utiliser Designer avec UserControls, vous n'avez donc pas à perdre de temps à écrire du code GUI fastidieux.

Euphorique
la source
Eh bien, le formulaire de base a simplement un SplitContainer avec Panel2 fixe, contenant un FlowLayoutPanel appelé BottomPanelet hébergeant les comportements communs Ok / Cancel / Apply / Close; Panel1 contient un SplitContainer avec Panel1 fixe (pour héberger une étiquette "d'instructions" commune, ou des menus, des barres d'outils, tout ce qui va en haut) et Panel2 contenant un Panel protégé appelé MainContent; chaque implémentation réelle décide comment la remplir. Tout le contenu peut être injecté dans l'implémentation et oui, cela peut être un contrôle utilisateur effectué avec le concepteur pour gagner du temps, bon point .. mais qu'en est-il du formulaire lui-même?
Mathieu Guindon
Le problème ici est l'échelle. Lorsque vous prenez une demande avec 10 formulaires, avoir un seul formulaire commun n'est pas un problème. Les problèmes commencent lorsque vous avez une application avec des dizaines ou des centaines de formulaires. Ensuite, vous aurez des formulaires qui ont des pièces communes, mais jamais assez pour créer un formulaire de base. Dans votre cas, il peut arriver que vous souhaitiez utiliser une disposition ou des boutons différents, mais que tout le reste reste le même. Et c'est là que les problèmes commencent.
Euphoric
2
Le «problème d'échelle» n'existe pas si vous avez une conception à moitié décente. Nous avons un projet où je travaille avec quelques centaines de formulaires. Nous utilisons fortement l'héritage de formulaires pour fournir de la cohérence et des fonctionnalités communes, et nous n'avons jamais eu de problèmes avec elle.
Mason Wheeler
2
@MasonWheeler J'ai eu une expérience exactement opposée. Nous avons essayé d'utiliser l'héritage de formulaires dans l'une de nos applications, et chaque fois que nous faisions même peu de changements dans les formulaires de base, le tout tombait en panne et nous devions corriger manuellement tous les autres formulaires. De plus, le concepteur se comporte bizarrement lorsque vous travaillez avec une forme héritée.
Euphoric
1
@Euphoric: Quel designer? Nous utilisons Delphi, et son concepteur fonctionne très bien avec les formes héritées. Et encore une fois, vous n'avez pas ces problèmes si vous avez un bon design . Si vous ne planifiez rien, bien sûr, tout sera fragile et se cassera à chaque fois que vous le toucherez, mais ce n'est pas différent de tout autre code.
Mason Wheeler
2

Une grande partie de cela est liée à la pile technologique de choix.

WinForms et WPF peuvent tous deux être des cadres d'interface utilisateur .NET mais varient considérablement dans la façon dont vous atteignez l'objectif final. Certains paradigmes évoluent très bien entre les technologies, mais d'autres ne le font pas et vous ne devriez pas essayer de forcer un paradigme simplement parce que vous sentez qu'il est censé exister dans tous les cadres. Il y a une raison pour laquelle MVVM est adapté à WPF / SL et MVC est un concept séparé dans ASP.NET à partir de WebForms et ainsi de suite. Certaines technologies fonctionnent mieux avec certains paradigmes.

Gardez à l'esprit que le code généré doit généralement être supprimé de vos préoccupations SECHES. Bien qu'applicable dans certains cas, il doit le plus souvent être ignoré. Les concepts DRY doivent certainement rester un focus en dehors de votre couche Présentation, mais au niveau de la couche Présentation, le code généré est le plus souvent un sous-produit du cadre dans lequel vous travaillez. Cela ne veut pas dire que vous ne pouvez pas appliquer les principes DRY dans votre approche, mais restez prudent. Pourriez-vous créer un formulaire de base et en hériter indéfiniment? Oui. Pourriez-vous faire glisser et déposer des composants sur un nouveau formulaire chaque fois que nécessaire? Oui. Restez concentré sur l'objectif final, en évitant les défauts potentiels, en facilitant la refactorisation en aval et l'évolutivité tout en travaillant dans les limites de la pile technologique de votre choix.

Aaron McIver
la source
0

Vous pouvez utiliser l'héritage à condition d'encapsuler correctement vos champs et de remplir en conséquence. Si vous souhaitiez utiliser l'héritage, ma suggestion serait d'avoir le formulaire de base et un modèle correspondant pour ce formulaire, et pour chaque dérivation dériver à la fois le formulaire et le modèle.

Une bien meilleure alternative serait de regrouper les contrôles associés en un ou plusieurs contrôles UserControl. Vous avez juste besoin d'un peu de logique pour y mettre les données pertinentes.

Sam
la source
0

Je suis totalement d'accord avec Mason Wheeler, même si en trois ans peut-être même lui-même avait changé d'avis.

J'essaie de chercher des alternatives pour migrer des exécutables Delphi vers le WEB.

Jusqu'à présent, je me suis décidé pour UNIGUI, car je peux toujours utiliser l'héritage de formulaire. J'aimerais que Delphi ait des Mixins comme Dart, car cela me permettrait d'avoir moins d'ancêtres. Mais je pense que les gens écrivent beaucoup plus de code dans MVC qu'avec Visual Form Inheritance, car la plupart de la navigation, les appels aux règles de validation dans le module de données (applyupdates), les critères de filtrage sql, la recherche dans le jeu de données client, tout est écrit en 5 peut-être 6 Former des ancêtres.

Même le "Avec MVC, il sera plus facile pour vous de laisser Delphi dans la fonctionnalité" pour moi ne fonctionne pas comme un argument, puisque les gens ont invité la POO, tout est classes, propriétés, méthodes. Je n'ai donc besoin que d'un traducteur. Je n'ai vraiment pu trouver aucun avantage, peut-être pour des sites Web qui sont beaucoup moins compliqués mais changent dans une base quotidienne.

user3145857
la source