O padrão de visitante é um mecanismo para simular a ligação dupla em linguagens de programação que suportam apenas a ligação única. Infelizmente, essa afirmação pode não esclarecer muito as coisas, então deixe-me explicar com um exemplo simples.
No .NET e C #, a plataforma que você está usando, os objetos podem ser convertidos em strings usando a ToString()
função O que essa função faz, ou seja, o código que está sendo executado, depende do tipo de objeto ao qual você está aplicando (é um método virtual). O código executado depende de uma coisa, o único tipo do objeto; portanto, o mecanismo usado é chamado de ligação única.
Mas e se eu quiser ter mais de uma maneira de converter um objeto em uma string, para cada tipo diferente de objeto? E se eu quisesse ter duas maneiras de converter objetos em seqüências de caracteres, para que o código que está sendo executado dependa de duas coisas: não apenas o objeto a ser convertido, mas também a maneira pela qual queremos que ele seja convertido?
Isso poderia ser resolvido bem se tivéssemos dupla ligação. Mas a maioria dos idiomas OO, incluindo C #, suporta apenas ligação única.
O padrão de visitante resolve o problema, transformando a ligação dupla em duas ligações simples sucessivas.
No nosso exemplo acima, ele usaria um método virtual no objeto para converter, que chama um segundo método virtual no objeto que implementa o algoritmo de conversão.
Mas isso implica que o objeto no qual você deseja aplicar o algoritmo precisa colaborar com isso: ele precisa ter suporte para o padrão de visitante inserido.
Você parece estar usando as classes Windows Forms do .NET, que não têm suporte para o padrão de visitantes. Mais especificamente, eles precisariam ter um public virtual void Accept(IVisitor)
método, o que obviamente eles não têm.
Então, qual é a alternativa? Bem, o .NET não suporta apenas a ligação única, mas também a ligação dinâmica, que é ainda mais eficiente que a ligação dupla.
Para obter mais informações sobre como aplicar essa técnica, que permitirá que você resolva seu problema (se bem entendi), dê uma olhada no Farewell Visitor .
ATUALIZAR:
Para aplicar a técnica ao seu problema específico, primeiro defina seu método de extensão:
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;
}
Crie o expedidor dinâmico:
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);
}
Em seguida, preencha os métodos específicos:
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
}