Visitor Pattern

Originally published 2016-05-13 · Boris Ivanov

1. Usage

Adds new operations to existing object structure without modifying that structure. Separates an algorithm from an object structure on which it operates.

Example:
An example would be a guest visiting a household. A guest talks to each family member, but he talks to each one in a different way – he will not talk the same with adults as he will with children. The guest has indispensable knowledge of how to talk to certain household member. This knowledge however does not have an impact on the household.

2. UML class diagram

Visitor Design Pattern

The Visitor can visit objects that dont have a common parent class.

Although the ConcreteElement nodes may represent unrelated classes, they all should derive from a common Element base.

The client instantiates a ConcreteVisitor.

The traversal algorithm invokes Element::accept(Visitor) for each node.

The ConcreteElement calls Visitor::visit(ConcreteElement).

The ConcreteVisitor now uses the ConcreteElement interface to carry out node-specific tasks.

3. Pros

4. Cons

5. Source code


// From http://www.patterns.pl/visitor.html
    #include <iostream>
    #include <vector>
    using namespace std;
    class ConcreteElementA;
    class ConcreteElementB;
    class Visitor
    {
    public:
      virtual void visitConcreteElementA(ConcreteElementA& visitable) = 0;
      virtual void visitConcreteElementB(ConcreteElementB& visitable) = 0;
    };
    class ConcreteVisitor : public Visitor
    {
    public:
      void visitConcreteElementA(ConcreteElementA& visitable) override
      {
        cout << "ConcreteVisitor perform opetation on ConcreteElementA" << endl;
      }
      void visitConcreteElementB(ConcreteElementB& visitable) override
      {
        cout << "ConcreteVisitor perform operation on ConcreteElementB" << endl;
      }
    	
    };
    class Visitable
    {
    public:
      virtual void accept(Visitor& visitor) = 0;
    };
    class ConcreteElementA : public Visitable
    {
    public:
      void accept(Visitor &visitor) override { visitor.visitConcreteElementA(*this); }
    };
    class ConcreteElementB : public Visitable
    {
    public:
      void accept(Visitor &visitor) override { visitor.visitConcreteElementB(*this); }
    };
    // Composite in practice
    class ObjectStructure : public Visitable
    {
      vector<Visitable*> elements;
    public:
      ObjectStructure() {}
      void addElement(Visitable *element) { elements.push_back(element); }
      void accept(Visitor &visitor) override
      {
        for (auto &e : elements)
        {
          e->accept(visitor);
        }
      }
    };
    int main()
    {
      ConcreteVisitor visitor;
      ConcreteElementA elementA;
      ConcreteElementB elementB;
      ObjectStructure objectStructure;
      objectStructure.addElement(&elementA);
      objectStructure.addElement(&elementB);
      objectStructure.accept(visitor);
      return 0;
    }