DCSIMG
Visitor Pattern - Gil Fink's Blog

Gil Fink's Blog

Fink about IT

News

Microsoft MVP

My Facebook Profile My Twitter Profile My Linkedin Profile

Locations of visitors to this page

Creative Commons License

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
© Copyright 2013 Gil Fink

Hebrew Articles

Index Pages

My OSS Projects

English Articles

Visitor Pattern

Visitor Pattern

The post will describe why and how to use the visitor design pattern and will
have a C# example of how to implement the pattern.
You can read my previous posts about design patterns here:
Structural patterns
Decorator pattern 
Proxy pattern
Facade pattern
Adapter pattern
Composite pattern
Bridge pattern
Flyweight pattern

Creational patterns
Singleton pattern
Abstract Factory pattern
Prototype pattern
Factory Method pattern
Builder pattern

Behavioral Patterns
Strategy pattern
Iterator pattern 
Template method pattern
Command pattern
Chain of responsibility pattern 
Mediator pattern
Memento pattern
State pattern

Visitor Pattern   
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    
Visitor Pattern     

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

    {

        // 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
an inner list. You can use whatever object structure you need in order to
implement the pattern. As can be seen in the example, I use two main
interfaces to implement the pattern – IVisitor and IElement. The IElement
dictates the Accept method to the Element abstract class which every concrete
element implement (I could drop the IElement or the Element class but I have chosen
not to). Every visitor concrete implement the Visit operation to perform the
desired operation (in my implementation the Visit method is implement the same in
both concrete classes).

The next code shows an example of how to use the classes above:

   // 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 the post, 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.
The next pattern I’ll cover will be the observer pattern.

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# August 3, 2008 1:35 PM

Rotem Bloom said:

Great article and explanation thanks.

# August 4, 2008 4:03 AM

Gil Fink said:

Thanks Rotem :-)

# August 4, 2008 4:58 AM

Visitor Pattern said:

Great Post

# October 23, 2008 6:13 PM

Gil Fink said:

Thanks Visitor Pattern

# October 24, 2008 2:43 AM