The Visitor Pattern – Design Patterns I.

It is a common problem that a feature involves of processing elements of a class hierarchy based on their exact type. Using virtual functions is a plausible solution but can be cumbersome if too many features are implemented that way. To decouple the hierarchy of entities and the processing algorithm Visitor pattern is the way to go. See the following examples:

  1. There are several types of customers stored in the system. Depending on the type of customer you want to send an Xmas greeting. Enterprise customers are contacted by email, SMS goes to private customers and a memo is added to an external CMS system for every long-term customer. The feature must be designed without significantly changing the existing class structure and keep it as flexible as possible (later Eastern greetings might be needed).
  2. In a banking application different sort of account types are handled. At the end of the month a report must be generated per account including account type dependent information. The format of these reports can vary. The reporting process should be easily configurable and open for future changes.

Solution: The feature is implemented in a Visitor class that is dynamically called from entities. As a consequence the feature and the class structure of entities are well separated. UML draft of the Visitor Pattern UML draft of the Visitor Pattern

Alternative solution 1: An obvious way is to use virtual methods. A base entity class declares an abstract virtual method and every derived class implements it. Then every client call is resolved to the proper instance. This solution is pretty straightforward; however, it affects the class structure even if the implemented feature is not strongly related to it. It can be also cumbersome to make the feature configurable.

Alternative solution 2: Another possibility is to use a static utility method that takes an entity as its parameter. The body of the method is based on a large switch – case statement over the type of the entity. This is a simple and effective solution if the class hierarchy of entities are simple and re-usability is not an issue.

Sample: Below you can find a sample code that corresponds to Example 1.

namespace VisitorPattern
{
    class Client
    {
        static void Main(string[] args)
        {
            Customer[] customers = new Customer[]{};
            XmasCardVisitor xmasCardVisitor = new XmasCardVisitor();
            foreach (Customer c in customers)
            {
                c.Accept(xmasCardVisitor);
            }
        }
    }

    public interface IVisitor
    {
        void Visit(EnterpriseCustomer c);
        void Visit(PrivateCustomer c);
        void Visit(LongTermCustomer c);
    }

    public class XmasCardVisitor : IVisitor
    {
        public void Visit(EnterpriseCustomer c)
        {
            //TODO
        }

        public void Visit(PrivateCustomer c)
        {
            //TODO
        }

        public void Visit(LongTermCustomer c)
        {
            //TODO
        }
    }

    public abstract class Customer
    {
        public abstract void Accept(IVisitor visitor);
    }

    public class EnterpriseCustomer : Customer
    {
        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class PrivateCustomer : Customer
    {
        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    public class LongTermCustomer : Customer
    {
        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

}