BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 2.0+

Visitor Design Pattern

The visitor pattern is a design pattern that separates a set of structured data from the functionality that may be performed upon it. This promotes loose coupling and enables additional operations to be added without modifying the data classes.

What is the Visitor Pattern?

The visitor pattern is a Gang of Four design pattern. This is a behavioural pattern as it defines a manner for controlling communication between classes or entities. The visitor pattern is used to separate a relatively complex set of structured data classes from the functionality that may be performed upon the data that they hold. This allows the creation of a data model with limited internal functionality and a set of visitors that perform operations upon the data. The pattern specifically allows each of the elements of a data structure to be visited in turn without knowing the details of the structure beforehand.

The key benefit of separating the data model from the algorithms that may be applied to it is the ability to add new operations easily. The classes of the data structure are initially created with the inclusion of a method that may be called by a visitor object. This method performs a callback to the visitor, passing itself to the visitor's method as a parameter. The visitor can then perform operations upon the data object. To add a new operation, a new visitor class is created with the appropriate callback method. The data classes need no further modification.

A second benefit of the design pattern is that a single visitor object is used to visit all elements of the data structure. The visitor object can maintain state between calls to individual data objects.

An example of the use of the visitor design pattern could be used within a personnel system. The data structure could define a hierarchy of managers and employees, each with a salary property. This system could include two visitor algorithms. The first would traverse the hierarchy and generate monthly salary payments. The second could apply a standard pay increase to each employee.

Implementing the Visitor Pattern

Visitor Design Pattern UML

The UML class diagram above shows an implementation of the visitor design pattern. The items in the diagram are described below:

  • Client. The Client class is a consumer of the classes of the visitor design pattern. It has access to the data structure objects and can instruct them to accept a Visitor to perform the appropriate processing.
  • ObjectStructure. The ObjectStructure class holds all of the elements of the data structure that can be used by visitors. The elements may be held in a simple collection or a more complex structure. The class includes a method, in the above diagram named "Accept", that can be called by the client with a Visitor object passed as a parameter. The ObjectStructure class then enumerates the contained elements, calling the Accept method of each and passing the provided Visitor. This allows each element to be processed without the client requiring any knowledge of the elements beforehand.
  • ElementBase. This abstract class is the base class for all element objects. It defines the accept method that each element must implement in order to be visited.
  • ConcreteElement A/B. Concrete element objects are those that hold real information in the data structure. To enable their use with the visitor design pattern, each must implement the Accept method. Usually the Accept method simply performs a callback to the visitor object. When the callback is made, the element object is passed to the visitor's Visit method so that it may execute an algorithm using the element's data.
  • VisitorBase. This class is the abstract base class for all concrete visitors. It defines a method, in the above diagram named "Visit", that can be called by element objects during the callback process. The method is generally overloaded with a version that is capable of processing any of the concrete element types.
  • ConcreteVisitor A/B. The concrete visitor classes contain the operations that are applied to the concrete element objects. They implement the various overloaded Visit methods defined in the VisitorBase class.

The following shows the basic code of the visitor design pattern implemented using C#. To simplify the example the code uses C# 3.0 automatically implemented property syntax to define properties. For earlier versions of the language you should use full property declarations with backing variables.

public class ObjectStructure
{
    public List<ElementBase> Elements { get; private set; }

    public ObjectStructure()
    {
        Elements = new List<ElementBase>();
    }

    public void Accept(VisitorBase visitor)
    {
        foreach (ElementBase element in Elements)
        {
            element.Accept(visitor);
        }
    }
}


public abstract class ElementBase
{
    public abstract void Accept(VisitorBase visitor);
}


public class ConcreteElementA : ElementBase
{
    public override void Accept(VisitorBase visitor)
    {
        visitor.Visit(this);
    }

    public string Name { get; set; }
}


public class ConcreteElementB : ElementBase
{
    public override void Accept(VisitorBase visitor)
    {
        visitor.Visit(this);
    }

    public string Title { get; set; }
}


public abstract class VisitorBase
{
    public abstract void Visit(ConcreteElementA element);

    public abstract void Visit(ConcreteElementB element);
}


public class ConcreteVisitorA : VisitorBase
{
    public override void Visit(ConcreteElementA element)
    {
        Console.WriteLine("VisitorA visited ElementA : {0}", element.Name);
    }

    public override void Visit(ConcreteElementB element)
    {
        Console.WriteLine("VisitorA visited ElementB : {0}", element.Title);
    }
}


public class ConcreteVisitorB : VisitorBase
{
    public override void Visit(ConcreteElementA element)
    {
        Console.WriteLine("VisitorB visited ElementA : {0}", element.Name);
    }

    public override void Visit(ConcreteElementB element)
    {
        Console.WriteLine("VisitorB visited ElementB : {0}", element.Title);
    }
}
21 August 2009