The visitor design pattern enables us to create new operations to be performed on an existing structure. The new operations don’t change the classes/nodes.
With the pattern you define two class hierarchies. The first for the elements which the operations will operate on. The second is for the visitors that define the operations on the elements.
The pattern is rarely used but it is common in compilers implementation.
Use Cases for the Visitor Pattern
You should use the pattern in the following cases:
- You have a class hierarchy with many distinct operations.
- The classes that defined in the object structure rarely change, but you need sometimes to define new operations on the object structure.
UML Diagram
Example in C#
The following code is an example of how to implement the pattern:
#region Visitor
public interface IVisitor
{
#region Methods
void Visit(Element element);
#endregion
}
#endregion
#region Visitor Concrete
public class VisitorConcreteA : IVisitor
{
#region IVisitor Members
public void Visit(Element element)
{
Console.WriteLine("{0} Visited {1}", this.GetType().Name, element.GetType().Name);
}
#endregion
}
public class VisitorConcreteB : IVisitor
{
#region IVisitor Members
public void Visit(Element element)
{
Console.WriteLine("{0} Visited {1}", this.GetType().Name, element.GetType().Name);
}
#endregion
}
#endregion
#region Element
public interface IElement
{
#region Methods
void Accept(IVisitor visitor);
#endregion
}
public abstract class Element : IElement
{
#region IElement Members
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
#endregion
}
#endregion
#region Concrete Element
public class ElementConcreteA : Element
{
}
public class ElementConcreteB : Element
{
}
#endregion
#region Object Structure
public class ObjectStructure
{
#region Members
private List<Element> _elements;
#endregion
#region Ctor
public ObjectStructure()
{
_elements = new List<Element>();
}
#endregion
#region Methods
public void AttachElement(Element element)
{
_elements.Add(element);
}
public void DetachElement(Element element)
{
_elements.Remove(element);
}
public void Accept(IVisitor visitor)
{
foreach (Element element in _elements)
{
element.Accept(visitor);
}
}
#endregion
}
#endregion
In the example I use an object structure that is implemented with inner list. You can use whatever object structure you need in order to the pattern.
As can be seen in the example, I use two main interfaces to implement the pattern – IVisitor
and IElement
.
The IElement
interface adds the Accept
method to the Element
abstract class which every concrete element implements (I could drop the IElement
interface or the Element
class but I have chosen not to).
Every visitor implements the Visit
operation to perform the desired operation (in my implementation the Visit
method is implemented the same in both concrete classes).
The next code shows an example of how to use the classes above:
ObjectStructure structure = new ObjectStructure();
structure.AttachElement(new ElementConcreteA());
structure.AttachElement(new ElementConcreteB());
VisitorConcreteA visitorA = new VisitorConcreteA();
VisitorConcreteB visitorB = new VisitorConcreteB();
structure.Accept(visitorA);
structure.Accept(visitorB);
Console.Read();
Summary
To sum up, you were introduced to the visitor design pattern. The pattern is used in order to extend elements of an object structure with new operations without the need to change the elements.
As written earlier the pattern is rarely used.