首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解访客模式

理解访客模式
EN

Software Engineering用户
提问于 2013-10-23 12:38:33
回答 1查看 13.6K关注 0票数 16

我有一个表示GUI控件的类的层次结构。就像这样:

代码语言:javascript
复制
Control->ContainerControl->Form

我必须实现一系列的算法,这些算法与对象一起工作,执行各种任务,我认为访问者模式将是最干净的解决方案。例如,一个创建对象层次结构的Xml表示的算法。使用“经典”方法,我会这样做:

代码语言:javascript
复制
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;
    }
}

但我不知道该怎么处理访客模式。这是基本的实现:

代码语言:javascript
复制
public class ToXmlVisitor : IVisitor
{
    public void Visit(Form form)
    {
    }
}

因为即使是抽象类也可以帮助实现,所以我不知道如何在ToXmlVisitor中正确地做到这一点?

我之所以考虑访问者模式,是因为有些算法需要在实现类的项目中不可用的引用,而且有许多不同的算法,所以我避免使用大型类。

EN

回答 1

Software Engineering用户

回答已采纳

发布于 2013-10-23 15:00:49

访问者模式是一种在只支持单个绑定的编程语言中模拟双重绑定的机制。不幸的是,这句话可能不太清楚,所以让我用一个简单的例子来解释一下。

在您使用的平台.NET和C#中,可以使用ToString()函数将对象转换为字符串。该函数的作用,即正在执行的代码,取决于应用它的对象的类型(它是一个虚拟方法)。执行什么代码取决于一件事,即对象的一种类型,因此所使用的机制称为单一绑定。

但是,如果我希望有不止一种方法将对象转换为字符串,对于每种不同类型的对象,又会怎样呢?如果我希望有两种方法将对象转换为字符串,那么执行的代码取决于两件事:不仅要转换对象,还需要转换它的方式。

如果我们有双重绑定,就能很好地解决这个问题。但是大多数OO语言,包括C#,只支持单个绑定。

访问者模式通过将双重绑定转换为两个连续的单个绑定来解决这个问题。

在上面的示例中,它将使用对象中的一个虚拟方法进行转换,该方法在实现转换算法的对象中调用第二个虚拟方法。

但这意味着要应用该算法的对象需要与此协作:它需要对访问者模式的支持。

您似乎在使用.NET的Windows窗体类,这些类不支持访问者模式。更具体地说,他们需要一个public virtual void Accept(IVisitor)方法,显然他们没有这个方法。

那么,还有别的选择吗?.NET不仅支持单一绑定,还支持动态绑定,这比双绑定更加有效。

有关如何应用该技术的更多信息,这将使您能够解决问题(如果我对此非常了解的话),请查看告别访客

更新:

要将该技术应用于特定问题,首先定义扩展方法:

代码语言:javascript
复制
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;
}

创建动态调度程序:

代码语言:javascript
复制
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);
}

然后填写具体方法:

代码语言:javascript
复制
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
}
票数 17
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/215350

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档