Visitor em C#
O Visitor é um padrão de projeto comportamental que permite adicionar novos comportamentos à hierarquia de classes existente sem alterar nenhum código existente.
Leia por que os Visitors não podem ser simplesmente substituídos pela sobrecarga de método em nosso artigo Visitor e Double Dispatch.
Complexidade:
Popularidade:
Exemplos de uso: O Visitor não é um padrão muito comum devido à sua complexidade e aplicabilidade limitada.
Exemplo conceitual
Este exemplo ilustra a estrutura do padrão de projeto Visitor. Ele se concentra em responder a estas perguntas:
- De quais classes ele consiste?
- Quais papéis essas classes desempenham?
- De que maneira os elementos do padrão estão relacionados?
Program.cs: Exemplo conceitual
using System; using System.Collections.Generic; namespace RefactoringGuru.DesignPatterns.Visitor.Conceptual { // The Component interface declares an `accept` method that should take the // base visitor interface as an argument. public interface IComponent { void Accept(IVisitor visitor); } // Each Concrete Component must implement the `Accept` method in such a way // that it calls the visitor's method corresponding to the component's // class. public class ConcreteComponentA : IComponent { // Note that we're calling `VisitConcreteComponentA`, which matches the // current class name. This way we let the visitor know the class of the // component it works with. public void Accept(IVisitor visitor) { visitor.VisitConcreteComponentA(this); } // Concrete Components may have special methods that don't exist in // their base class or interface. The Visitor is still able to use these // methods since it's aware of the component's concrete class. public string ExclusiveMethodOfConcreteComponentA() { return "A"; } } public class ConcreteComponentB : IComponent { // Same here: VisitConcreteComponentB => ConcreteComponentB public void Accept(IVisitor visitor) { visitor.VisitConcreteComponentB(this); } public string SpecialMethodOfConcreteComponentB() { return "B"; } } // The Visitor Interface declares a set of visiting methods that correspond // to component classes. The signature of a visiting method allows the // visitor to identify the exact class of the component that it's dealing // with. public interface IVisitor { void VisitConcreteComponentA(ConcreteComponentA element); void VisitConcreteComponentB(ConcreteComponentB element); } // Concrete Visitors implement several versions of the same algorithm, which // can work with all concrete component classes. // // You can experience the biggest benefit of the Visitor pattern when using // it with a complex object structure, such as a Composite tree. In this // case, it might be helpful to store some intermediate state of the // algorithm while executing visitor's methods over various objects of the // structure. class ConcreteVisitor1 : IVisitor { public void VisitConcreteComponentA(ConcreteComponentA element) { Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor1"); } public void VisitConcreteComponentB(ConcreteComponentB element) { Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor1"); } } class ConcreteVisitor2 : IVisitor { public void VisitConcreteComponentA(ConcreteComponentA element) { Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor2"); } public void VisitConcreteComponentB(ConcreteComponentB element) { Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor2"); } } public class Client { // The client code can run visitor operations over any set of elements // without figuring out their concrete classes. The accept operation // directs a call to the appropriate operation in the visitor object. public static void ClientCode(List<IComponent> components, IVisitor visitor) { foreach (var component in components) { component.Accept(visitor); } } } class Program { static void Main(string[] args) { List<IComponent> components = new List<IComponent> { new ConcreteComponentA(), new ConcreteComponentB() }; Console.WriteLine("The client code works with all visitors via the base Visitor interface:"); var visitor1 = new ConcreteVisitor1(); Client.ClientCode(components,visitor1); Console.WriteLine(); Console.WriteLine("It allows the same client code to work with different types of visitors:"); var visitor2 = new ConcreteVisitor2(); Client.ClientCode(components, visitor2); } } } Output.txt: Resultados da execução
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1 It allows the same client code to work with different types of visitors: A + ConcreteVisitor2 B + ConcreteVisitor2