Pattern Visiteur et Decorateur - C#/.NET managed - Programmation
Marsh Posté le 18-05-2007 à 01:08:24
J'ai rien pigé
C'est quoi ces histoires de visiteurs et décorateur ?
Et pourquoi t'as un visiteur en béton ? (concrete chez moi ça veut dire béton en anglais )
Marsh Posté le 18-05-2007 à 01:14:41
MagicBuzz a écrit : J'ai rien pigé C'est quoi ces histoires de visiteurs et décorateur ? |
-------
IVisitor à une méthode Visit(XObj) ? (w doi être XObj et pas XObj1 ou 2 non ?) (verifie via le debugueur - bref, c'est quoi les types des objets qui sont dans ta listes)
Par contre, ce qui m'étonne, c'est que ton décorateur n'hérite pas de XObj (et en quoi il décore, en fait ?)
(je supose que XObj1 et 2 hérite de XObj)
Marsh Posté le 18-05-2007 à 02:41:44
MagicBuzz a écrit : J'ai rien pigé |
je pense que la lecture de ce bouquin s'impose : http://www.amazon.fr/Design-patter [...] 2841773507
Marsh Posté le 18-05-2007 à 11:06:21
Ben si ça va pas chercher plus loin que ça, y'a pas besoin d'acheter un bouquin à 56 pour savoir ce que c'est.
http://en.wikipedia.org/wiki/Visitor_pattern
http://en.wikipedia.org/wiki/Double_dispatch
http://www.exciton.cs.rice.edu/Jav [...] attern.htm
http://nice.sourceforge.net/visitor.html
=> Le dernier lien semble contredire la conclusion du second non ? Lequel est dans le vrai dans cas du C# ? Notamment, l'exemple de l'utilité du double dispatching s'applique au C++ qui est présenté dans l'exemple ayant des lacunes du point de vue de la gestion des surcharges. Qu'en est-il avec le C# ? Parceque moi je trouve aussi que simplement dériver tous mes objets de la même interface est une solution plus propre et surtout, moins chiante à coder/relire (le code est dans la classe, pas dans une classe qui n'a rien à voir et qu'on n'atteind qu'à force d'appels récursifs)
Marsh Posté le 18-05-2007 à 11:50:24
MagicBuzz a écrit : (le code est dans la classe, pas dans une classe qui n'a rien à voir et qu'on n'atteind qu'à force d'appels récursifs) |
Si ta modélisation est mal foutu, forcement, ça n'aide pas.
si tu attaque la classe parente de ta classe parente, il y a un problème.
Marsh Posté le 18-05-2007 à 12:07:02
Ben non. Regarde l'exemple du premier lien.
Le code relatif à l'affichage de "Car", "Wheel" et autres se trouve non pas dans les classes en question, mais dans le visiteur (PrintVisitor) au lieu d'être dans chacune des classes.
Pour moi, il serait plus judicieux de faire une interface IPrintable, contenant "Print()" et en faire hériter toutes les classes en question.
=> Ainsi, le code relatif à l'impression sont directement dans les objets plutôt que dans un objet qui y fait référence, et qui est appelé par ces objets en question.
Bon, l'exemple est très succint, et il y a certainement des cas où l'intérêt est réel, mais là je vois pas trop.
Le seul intérêt à mes yeux est celui annoncé au départ : si on veut modifier le comportement de "Print()" on peut n'a pas besoin de modifier les objets "parents", tout le code relatif à l'impression se trouve dans la même classe. Mais bon, avec la clause "partial", on peut parfaitement en C# regrouper tout le code relatif à l'impression de tous les objets dans un fichier dédié, donc ensuite l'intérêt me semble assez maigre.
Le second intérêt (mais est-ce un intérêt) c'est que les objets "parents" ne fond plus de références croisés entre eux, c'est la class visteur qui s'en charge. Mais à nouveau, à quoi ça sert ? (dans l'exemple de la classe Car, il fait de toute façon déjà références aux autres objets...)
Marsh Posté le 18-05-2007 à 12:16:11
non mais en fait, j'ai compris que tu faisais quelque chose genre
Code :
|
J'ai eux peur
MagicBuzz a écrit : |
Si il veut changer la méthode d'affichage des objets (en envoyant tout dans la sortie d'erreur par exemple), il n'a que le visiteur à modifier et pas toutes les classes Car, Wheel, etc.
Et en allant plus loin, si la personne implemente un adaptateur dans le visiteur, selon que tu sois en Debug ou Release par exemple, le programme peut sortir les informations soit sur la sortie standard (debug) soit dans un buffer (Release par exemple) ce qui n'est pas possible si tu mets ce code dans les classes Car, etc à moins de forcer ça quelque part.
(l'adaptateur va faire le choix selon la situation Debug ou Release)
Marsh Posté le 18-05-2007 à 12:26:14
Ben moi dans ces cas, je fais une classe "Afficheur", et c'est lui qui s'occupe de faire ça proprement. Mais c'est les objets eux-même qui lui disent quoi afficher.
Ceci dit, je comprends parfaitement ton explication en ce qui concerne un changement de comportement de l'affichage pour toutes les méthodes d'un coup.
Mais dans ce cas, je te renvois à la clause "partial", qui permet de pallier à un certain nombre de problèmes sans problème.
(Bon, pas complètement, genre si "Visitor" contiens aussi des méthodes privées partagées entre tous les Print(), je suis d'accord que là c'est baisé si tu ne passes pas par cette structure
Marsh Posté le 18-05-2007 à 12:30:52
MagicBuzz a écrit : |
J'ai jamais fais de C#
Marsh Posté le 18-05-2007 à 13:22:36
Ben partial, ça sert juste à dire "ce petit bout de code en fait, c'est un morceau de ma classe untel". Je pense qu'on a la même chose en Java.
Exemple :
interfaces.cs
Code :
|
voiture.cs
Code :
|
Roue.cs
Code :
|
couleur.cs
Code :
|
print.cs
Code :
|
truc.cs
Code :
|
program.cs
Code :
|
Sortie :
|
=> On voit dans cet exemple que tout ce qui est relatif à l'impression se situe dans le fichier "print.cs", alors que les méthodes d'affichage restent bel et bien dans les objets finaux.
-- Edit : Version corrigée avec un exemple qui marche
-- Edit² : Et plus complet
Marsh Posté le 19-05-2007 à 20:42:46
alors la ca m'interesse.
je ne connaissais pas le mot cle partial (c# 2 ?)
puis-je de cette maniere completer une classe que je n'ai pas ecrite ?
cad une classe qui se trouverait dans un framework qualconque ?
si oui, alors il me suffit de rajouter une methode d'acceptation de mon visiteur dans les classes issues de la bibliotheque que j'utilise (un decorateur qui ne dis pas son nom quoi !)
Edit:
bon a priori je me suis affole pour rien, ca ne fonctionne pas.
etant donne que je n'ai pas la main sur les objets de la bibliotheque je ne peux pas leur rajouter de comportement en utilisant partial.
Marsh Posté le 20-05-2007 à 11:38:33
il faut que les classes initiales soit dotée du mot clé partial.
Maintenant pour en revenir à son utilisation, ça doit être utilisé pour séparer le code d'une classe dans plusieurs fichiers. Si c'est pour complété tes objets, autant en dérivé et complété dans la classe fille.
oui PARTIAL est arrivé avec .NET 2.0
Marsh Posté le 21-05-2007 à 09:27:06
Je tiens à souligner que si "partial" part d'une très bonne idée, on remarque dans mon exemple plusieurs choses :
- Pour indiquer de quoi dérive une classe, il suffit d'indiquer les classes "parentes" dans un seul fichier. Je n'ai pas testé les mélanges, mais avec un peu de pas de chance, ça marche (genre dans un fichier, je dérive d'une interface, et dans un autre fichier, d'une autre). Dans ce cas, on remarque rapidement les problèmes de maintenance que cela peut impliquer...
- Partial peut être utilisé comme dans mon exemple, pour regrouper dans un même fichier toutes les surcharges de différentes classes dérivées d'une même interface, de façon à retrouver facilement le code. Le problème, c'est que rapidement ça peut se bordeliser, si une personne qui intervient sur le projet ne suit pas cette façon de "ranger" le code. Idem si un fichier servait à contenir les méthodes "métier" d'une classe. Si on ne suis pas la règle, on peut rapidement arriver à du code difficile à relire.
- L'implémentation "de base" en C# consiste à mettre dans un fichier spécial toute "l'initialisation" et "le design" des form dans un fichier, tandis que le code utilisateur se trouve dans un autre fichier. A nouveau, si le code "utilisateur" se met à faire de l'inisitlisation -notamment, on y trouve le constructeur- ou du design (présente de la méthode onpaint par exemple) on peut arriver à une lisibilitée très amoindrie : mais d'où vient cet objet ? il est initialisé comment ? et qu'est-ce qu'il fout ici au milieu de ma form ? etc.
Bref, à utiliser en faisant attention. En soit il peut être très pratique et utile, mais aussi s'avérer l'enemi juré de la maintenabilité du code, surtout si on n'utilise pas de GUI évoluée.
Marsh Posté le 17-05-2007 à 12:49:09
Bonjour,
j'utilise actuellement une bibliotheque qui a une fonction qui me renvoie une liste d'objets (XObj1, XObj2 qui derivent tous de XObj).
J'aimerais afficher cette liste en faisant un traitement different en fonction du type d'objet.
Pour cela, je souhaiterais utiliser un visiteur qui me parait la solution la plus souple.
Malheureusement, je ne peux modifier le code des objetx Xobj, Xobj1 Xobj2.
J'ai donc pensé a faire un decorateur qui dont voici le code :
class XObjectDecorator
{
private XObj _wow = null;
public XObjectDecorator(XObj w)
{
this._wow = w;
}
public void Accept(IVisitor v)
{
v.Visit(this._wow);
}
}
que j'utiliserais comme ceci :
ConcreteVisitor visit = new ConcreteVisitor();
new XObjectDecorator(gList.Object(i)).Accept(visit);
Malheureusement, a la compilation j'ai l'erreur suivant sur v.visit(this._wow) :
Erreur 1 La méthode surchargée correspondant le mieux à 'IVisitor.Visit(XObj1)' possède des arguments non valides
Erreur 2 Argument '1' : impossible de convertir de 'XObj' en 'XObj1'
Je ne vois pas du tout ce qui ne va pas.
Auriez-vous une idee ?
merci d'avance
v.