Ich habe eine Hierarchie von Klassen, die GUI-Steuerelemente darstellt. Etwas wie das:
Control->ContainerControl->Form
Ich muss eine Reihe von Algorithmen implementieren, die mit Objekten arbeiten, die verschiedene Aufgaben ausführen, und ich denke, dass das Besuchermuster die sauberste Lösung wäre. Nehmen wir zum Beispiel einen Algorithmus, der eine XML-Darstellung einer Hierarchie von Objekten erzeugt. Unter Verwendung des klassischen Ansatzes würde ich dies tun:
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;
}
}
Aber ich bin mir nicht sicher, wie ich das mit dem Besuchermuster machen soll. Dies ist die grundlegende Implementierung:
public class ToXmlVisitor : IVisitor
{
public void Visit(Form form)
{
}
}
Da auch die abstrakten Klassen bei der Implementierung helfen, bin ich mir nicht sicher, wie ich das in ToXmlVisitor richtig machen soll?
Der Grund, warum ich das Besuchermuster in Betracht ziehe, ist, dass einige Algorithmen Referenzen benötigen, die in Projekten, in denen die Klassen implementiert sind, nicht verfügbar sind, und dass es eine Reihe verschiedener Algorithmen gibt, sodass ich große Klassen vermeide.
Antworten:
Das Besuchermuster ist ein Mechanismus zur Simulation der Doppelbindung in Programmiersprachen, die nur die Einzelbindung unterstützen. Leider könnte diese Aussage die Dinge nicht sehr klar machen. Lassen Sie mich dies anhand eines einfachen Beispiels erläutern.
In .NET und C #, der von Ihnen verwendeten Plattform, können Objekte mithilfe der
ToString()
Funktion in Zeichenfolgen konvertiert werden . Was diese Funktion, dh der ausgeführte Code, tut, hängt von der Art des Objekts ab, auf das Sie ihn anwenden (es ist eine virtuelle Methode). Welcher Code ausgeführt wird, hängt von einer Sache ab, dem einen Typ des Objekts. Daher wird der verwendete Mechanismus als Einzelbindung bezeichnet.Aber was ist, wenn ich mehr als eine Möglichkeit haben möchte, ein Objekt für jede Art von Objekt in einen String umzuwandeln? Was wäre, wenn ich zwei Möglichkeiten hätte, Objekte in Zeichenfolgen zu konvertieren, damit der auszuführende Code von zwei Dingen abhängt: nicht nur vom zu konvertierenden Objekt, sondern auch von der Art und Weise, wie wir es konvertieren möchten?
Das könnte gut gelöst werden, wenn wir eine doppelte Bindung hätten. Die meisten OO-Sprachen, einschließlich C #, unterstützen jedoch nur die Einzelbindung.
Das Besuchermuster löst das Problem, indem die Doppelbindung in zwei aufeinanderfolgende Einzelbindungen umgewandelt wird.
In unserem obigen Beispiel würde für die Konvertierung eine virtuelle Methode im Objekt verwendet, die eine zweite virtuelle Methode im Objekt aufruft, die den Konvertierungsalgorithmus implementiert.
Dies impliziert jedoch, dass das Objekt, auf das Sie den Algorithmus anwenden möchten, damit zusammenarbeiten muss: Es muss Unterstützung für das eingebrachte Besuchermuster haben.
Sie verwenden anscheinend .NETs Windows Forms-Klassen, die das Besuchermuster nicht unterstützen. Insbesondere müssten sie eine
public virtual void Accept(IVisitor)
Methode haben, die sie offensichtlich nicht haben.Also, was ist die Alternative? Nun, .NET unterstützt nicht nur die Einzelbindung, sondern auch die dynamische Bindung, die noch leistungsfähiger ist als die Doppelbindung.
Weitere Informationen zur Anwendung dieser Technik, mit der Sie Ihr Problem lösen können (sofern ich sie gut verstehe), finden Sie unter Farewell Visitor .
AKTUALISIEREN:
Um die Technik auf Ihr spezielles Problem anzuwenden, definieren Sie zunächst Ihre Erweiterungsmethode:
Erstellen Sie den dynamischen Dispatcher:
Füllen Sie dann die spezifischen Methoden aus:
quelle