Eu tenho uma hierarquia de classes que representa controles da GUI. Algo assim:
Control->ContainerControl->Form
Eu tenho que implementar uma série de algoritmos que funcionam com objetos fazendo várias coisas e estou pensando que o padrão Visitor seria a solução mais limpa. Tomemos, por exemplo, um algoritmo que cria uma representação XML de uma hierarquia de objetos. Usando a abordagem 'clássica', eu faria o seguinte:
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;
}
}
Mas não sei como fazer isso com o padrão de visitantes. Esta é a implementação básica:
public class ToXmlVisitor : IVisitor
{
public void Visit(Form form)
{
}
}
Como até as classes abstratas ajudam na implementação, não sei como fazer isso corretamente no ToXmlVisitor?
A razão pela qual estou considerando o padrão Visitor é que alguns algoritmos precisarão de referências não disponíveis no projeto em que as classes são implementadas e há vários algoritmos diferentes, por isso estou evitando grandes classes.
fonte
Respostas:
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:
Crie o expedidor dinâmico:
Em seguida, preencha os métodos específicos:
fonte