У меня есть иерархия классов, которая представляет элементы управления GUI. Что-то вроде этого:
Control->ContainerControl->Form
Я должен реализовать ряд алгоритмов, которые работают с объектами, делающими разные вещи, и я думаю, что шаблон Visitor будет самым чистым решением. Давайте возьмем, например, алгоритм, который создает представление XML иерархии объектов. Используя «классический» подход, я бы сделал это:
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;
}
}
Но я не уверен, как это сделать с помощью шаблона посетителя. Это базовая реализация:
public class ToXmlVisitor : IVisitor
{
public void Visit(Form form)
{
}
}
Так как даже абстрактные классы помогают с реализацией, я не уверен, как это сделать правильно в ToXmlVisitor?
Причина, по которой я рассматриваю шаблон Visitor, заключается в том, что некоторым алгоритмам потребуются ссылки, недоступные в проекте, где реализованы классы, и существует ряд различных алгоритмов, поэтому я избегаю больших классов.
Ответы:
Шаблон посетителя - это механизм для симуляции двойного связывания в языках программирования, которые поддерживают только одиночное связывание. К сожалению, это утверждение не может многое прояснить, поэтому позвольте мне объяснить на простом примере.
В используемой платформе .NET и C # объекты могут быть преобразованы в строки с помощью
ToString()
функции. То, что делает эта функция, т.е. выполняемый код, зависит от типа объекта, к которому вы применяете ее (это виртуальный метод). То, какой код выполняется, зависит от одной вещи, одного типа объекта, поэтому используемый механизм называется одиночным связыванием.Но что, если я хочу иметь более одного способа преобразования объекта в строку для каждого объекта другого типа? Что если бы я хотел иметь два способа преобразования объектов в строки, чтобы выполняемый код зависел от двух вещей: не только от объекта, который нужно преобразовать, но и от способа, которым мы хотим, чтобы он был преобразован?
Это можно было бы решить, если бы у нас было двойное связывание. Но большинство ОО-языков, включая C #, поддерживают только одну привязку.
Шаблон посетителя решает проблему, превращая двойное связывание в два последовательных одиночных связывания.
В нашем примере выше для преобразования используется виртуальный метод в объекте, который вызывает второй виртуальный метод в объекте, реализующем алгоритм преобразования.
Но это подразумевает, что объект, к которому вы хотите применить алгоритм, должен сотрудничать с этим: он должен иметь встроенную поддержку шаблона посетителя.
Похоже, вы используете классы .NET Windows Forms, которые не поддерживают шаблон посетителя. Точнее говоря, у них должен быть
public virtual void Accept(IVisitor)
метод, которого, очевидно, у них нет.Итак, какова альтернатива? Ну, .NET не только поддерживает одиночное связывание, но также поддерживает динамическое связывание, которое даже более эффективно, чем двойное связывание.
Для получения дополнительной информации о том, как применить эту технику, которая позволит вам решить вашу проблему (если я хорошо понимаю), посмотрите на Прощального посетителя .
ОБНОВИТЬ:
Чтобы применить метод к вашей конкретной проблеме, сначала определите метод расширения:
Создайте динамический диспетчер:
Затем заполните конкретные методы:
источник