J'ai une hiérarchie de classes qui représente des contrôles de l'interface graphique. Quelque chose comme ça:
Control->ContainerControl->Form
Je dois mettre en œuvre une série d'algoritmes qui fonctionnent avec des objets faisant diverses choses et je pense que le modèle de visiteur serait la solution la plus propre. Laissons prendre par exemple un algorithme qui crée une représentation XML d'une hiérarchie d'objets. En utilisant une approche "classique", je ferais ceci:
public abstract class Control
{
public virtual XmlElement ToXML(XmlDocument document)
{
XmlElement xml = document.CreateElement(this.GetType().Name);
// Create element, fill it with attributes declared with control
return xml;
}
}
public abstract class ContainerControl : Control
{
public override XmlElement ToXML(XmlDocument document)
{
XmlElement xml = base.ToXML(document);
// Use forech to fill XmlElement with child XmlElements
return xml;
}
}
public class Form : ContainerControl
{
public override XmlElement ToXML(XmlDocument document)
{
XmlElement xml = base.ToXML(document);
// Fill remaining elements declared in Form class
return xml;
}
}
Mais je ne suis pas sûr de la faire avec le motif de visiteur. C'est la mise en œuvre de base:
public class ToXmlVisitor : IVisitor
{
public void Visit(Form form)
{
}
}
Puisque même les classes abstraites aident à la mise en œuvre, je ne sais pas comment faire cela correctement dans Toxmlvisitor?
La raison que je considère que je considère que je considère que je envisageait que certains algorithmes auront besoin de références non disponibles dans le projet où les classes sont mises en œuvre et qu'il existe un certain nombre d'algorithmes différents, donc j'évite les grandes classes.
Le motif visiteur est un mécanisme permettant de simuler une double liaison dans les langages de programmation qui ne supportent que la liaison unique. Malheureusement, cette déclaration ne pourrait pas beaucoup clarifier les choses, alors laissez-moi vous expliquer avec un exemple simple.
Dans .NET et C #, la plate-forme que vous utilisez, les objets peuvent être convertis en chaînes à l'aide de la fonction ToString()
. Ce que cette fonction fait, c'est-à-dire le code exécuté, dépend du type d'objet que vous l'appliquez (c'est une méthode virtuelle). Quel code est exécuté dépend d'une chose, le type d'objet de l'objet, d'où le mécanisme utilisé s'appelle une liaison unique.
Mais si je veux avoir plus d'une façon de convertir un objet à une chaîne, pour chaque type d'objet différent? Et si je voulais avoir deux façons de convertir des objets en chaînes, de sorte que le code exécuté dépend de deux choses: non seulement l'objet à convertir, mais également la manière dont nous voulons que cela soit converti?
Cela pourrait être résolu bien si nous avions une double contraignante. Mais la plupart OO Langues, y compris C #, supporte uniquement la liaison unique.
Le motif de visiteur résout le problème en tournant la double liaison à deux reliures simples successives.
Dans notre exemple ci-dessus, il utiliserait une méthode virtuelle dans l'objet à convertir, qui appelle une deuxième méthode virtuelle dans l'objet mettant en œuvre l'algorithme de conversion.
Mais cela implique que l'objet sur lequel vous souhaitez appliquer l'algorithme doit collaborer avec cela: elle doit avoir le soutien du motif de visiteur au four.
Vous semblez utiliser les classes de formulaires Windows de .NET, qui n'ont pas de support pour le motif de visiteur. Plus spécifiquement, ils auraient besoin d'une méthode public virtual void Accept(IVisitor)
, ce qui n'a évidemment pas.
Alors, quelle est l'alternative? Eh bien, .NET ne supporte pas seulement la liaison unique, elle prend également en charge la liaison dynamique, ce qui est encore plus sexuelle que la couche double.
Pour plus d'informations sur la manière d'appliquer cette technique, qui vous permettra de résoudre votre problème (si je comprends bien), jetez un coup d'œil à visiteur d'adie .
Mise à jour:
Pour appliquer la technique à votre problème spécifique, définissez d'abord votre méthode d'extension:
public static XmlDocument ToXml(this Control control)
{
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement(control.GetType().Name);
xml.AppendChild(root);
Visit(control, xml, root);
return xml;
}
Créer le répartiteur dynamique:
private static void Visit(Control control, XmlDocument xml, XmlElement root)
{
dynamic dynamicControl = control; //notice the 'dynamic' type.
//this is the key to dynamic dispatch
VisitCore(dynamicControl, xml, root);
}
Ensuite, remplissez les méthodes spécifiques:
private static void VisitCore(Control control, XmlDocument xml, XmlElement root)
{
// TODO: specific Control handling
}
private static void VisitCore(ContainerControl control, XmlDocument xml, XmlElement root)
{
// call the "base" method
VisitCore(control as Control, xml, root);
// TODO: specific ContainerControl handling
// for example:
foreach (Control child in control.Controls)
{
XmlElement element = xml.CreateElement(child.GetType().Name);
root.AppendChild(element);
// call the dynamic dispatcher method
Visit(child, xml, element);
}
}
private static void VisitCore(Form control, XmlDocument xml, XmlElement root)
{
// call the "base" method
VisitCore(control as ContainerControl, xml, root);
// TODO: specific Form handling
}