The Visitor pattern uses an external class to act on data in other classes. This is a useful approach to you when you have a polymorphic operation that cannot reside in the class hierarchy. Visitor is also a useful way to extend the behavior of a class hierarchy without the need to alter existing classes or to implement the new behavior in every subclass that requires it.
I think the visitor pattern feels a bit of a weird pattern. I mean weird in a way that it feels not very object-oriented nor structured way of programming. On the other hand, sometimes you have a collection of similar classes which differ in one or more methods. If you don’t want to ‘pollute’ your object-oriented hierarchy with these class-specific methods, then you can use the visitor pattern.
All the client needs is an object structure, a visitor and an element. One or more elements are attached to the object structure. The visitor visits the object structure and does ‘something’ with the attached elements.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Client { static void Main() { ObjectStructure objectstructure = new ObjectStructure(); Element element = new ConcreteElement(); objectstructure.Attach(element); ConcreteVisitor visitor = new ConcreteVisitor(); objectstructure.Accept(visitor); Console.ReadKey(); } } |
The abstract class Visitor can have one or more concrete implementations, which do their work on the attached elements.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
abstract class Visitor { public abstract void VisitConcreteElement(ConcreteElement concreteElement); } class ConcreteVisitor : Visitor { public override void VisitConcreteElement(ConcreteElement concreteElement) { Console.WriteLine("{0} visited by {1}", concreteElement.GetType().Name, this.GetType().Name); } } |
The element class accepts a visitor and propagates an operation towards this visitor.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
abstract class Element { public abstract void Accept(Visitor visitor); } class ConcreteElement : Element { public override void Accept(Visitor visitor) { visitor.VisitConcreteElement(this); } public void Operation() { } } |
The object structure contains all machinery needed for maintenance of a list of attached elements. In this way it resembles the subject class of the observer pattern.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class ObjectStructure { private List m_Elements = new List(); public void Attach(Element element) { m_Elements.Add(element); } public void Detach(Element element) { m_Elements.Remove(element); } public void Accept(Visitor visitor) { foreach (Element element in m_Elements) { element.Accept(visitor); } } } |
By now you should get some idea how the visitor pattern works.
Handy? I am not sure, I never used it in real life. What do you think. Please let me know.
This post is part of a series on the foundational design patterns in C#. In this series we explore the ancient design patterns and their use in real-world programming situations of today. In these series of posts we explore each pattern by looking at a minimalistic example to reveal its structure and then look at more concrete and useful real-world C# code that implements the pattern.
Comments