using System; namespaceVisitorPatternDemo { // The Component interface declares an `accept` method that should take the // base visitor interface as an argument. publicinterfaceIComponent { voidAccept(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. publicclassConcreteComponentA : 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. publicvoidAccept(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. publicstringExclusiveMethodOfConcreteComponentA() { return"A"; } }
// 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. publicinterfaceIVisitor { voidVisitConcreteComponentA(ConcreteComponentA 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. classConcreteVisitor1 : IVisitor { publicvoidVisitConcreteComponentA(ConcreteComponentA element) { Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor1"); }
publicclassClient { // 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. publicstaticvoidClientCode(List<IComponent> components, IVisitor visitor) { foreach (var component in components) { component.Accept(visitor); } } }
classProgram { staticvoidMain(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
// 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 } } }