Click here to Skip to main content
15,886,362 members
Articles / Operations

Visitor Pattern

Rate me:
Please Sign up or sign in to vote.
4.89/5 (2 votes)
19 Oct 2013CPOL1 min read 8.8K   5  
The visitor design pattern enables us to create new operations to be performed on an existing structure. The new operations don’t change the

This articles was originally at wiki.asp.net but has now been given a new home on CodeProject. Editing rights for this article has been set at Bronze or above, so please go in and edit and update this article to keep it fresh and relevant.

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

Image 1

Example in C#

The following code is an example of how to implement the pattern:

C#
#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
    {
        // implement whatever you need
    }

    public class ElementConcreteB : Element
    {
        // implement whatever you need
    }
    #endregion

    #region Object Structure
    public class ObjectStructure
    {
        #region Members
        private List<Element> _elements;
        #endregion

        #region Ctor
        /// <summary>
        /// Construct a new object structure
        /// </summary>
        public ObjectStructure()
        {
            _elements = new List<Element>();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Attach the given element to the object structure
        /// </summary>
        /// <param name="element">The element to attach</param>
        public void AttachElement(Element element)
        {
            _elements.Add(element);
        }

        /// <summary>
        /// Detaches the given element from the object structure
        /// </summary>
        /// <param name="element">The element to detach</param>
        public void DetachElement(Element element)
        {
            _elements.Remove(element);
        }

        /// <summary>
        /// Perform accept operation on all the object structure
        /// with the given visitor
        /// </summary>
        /// <param name="visitor">The given visitor</param>
        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:

C#
// Build the structure
ObjectStructure structure = new ObjectStructure();
structure.AttachElement(new ElementConcreteA());
structure.AttachElement(new ElementConcreteB());

// Create visitor objects
VisitorConcreteA visitorA = new VisitorConcreteA();
VisitorConcreteB visitorB = new VisitorConcreteB();

// Structure accepting visitors
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.

This article was originally posted at http://wiki.asp.net/page.aspx/491/visitor-pattern

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
The ASP.NET Wiki was started by Scott Hanselman in February of 2008. The idea is that folks spend a lot of time trolling the blogs, googlinglive-searching for answers to common "How To" questions. There's piles of fantastic community-created and MSFT-created content out there, but if it's not found by a search engine and the right combination of keywords, it's often lost.

The ASP.NET Wiki articles moved to CodeProject in October 2013 and will live on, loved, protected and updated by the community.
This is a Collaborative Group

754 members

Comments and Discussions

 
-- There are no messages in this forum --