I think the name of the pattern Visitor is quite unfortunate.
Instead of the word visitor I would say Functor or Operator and instead of 'visit' I would say 'apply'.
My understanding of visitor pattern is as follows:
In template meta-programming (STL/BOOST) (compile time binding) you can achieve (the orthogonal design)
the separations of operations from structures, by the means of function objects (Functors.)
For example in
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
the comp is a functor/operator representing 'less than' operation in a very generic way, so you don't have to have many variants of sort function:
For Visitor pattern you want to achieve something similar but in the case of run time (late) binding:
You want to simplify the interface of A, you want to keep possibility for future extensions (new operations working with A) and you want to achieve the stability of interface of A in the case of those extensions.
From the original 'fat' class:
class A
{
public:
virtual void function_or_operation_1();//this can be implemented in terms of public interface of the other functions
virtual void function_or_operation_2();
//..etc
virtual void function_or_operation_N();
public:
//stable public interface, some functions of procedures
private:
//....
}
you remove as many function from public interface as possible (as long as they can be implemented in terms of the non-extracted functions of the same public interface )
and represent the operations as the functor objects or objects from a new Functor hierarchy:
You reduce the number of function in the base class A by having very generic interface using forward declared Functor_or_Operator:
class Functor_or_Operator;
class A
{
public:
virtual void apply(Functor_or_Operator*);//some generic function operates on this objects from A hierarchy
//..etc
public:
//stable public interface, some functions
private:
//....
}
//Now you have N(=3) classes in A hierarchy (A,B,C) and M operations or functions represented by classes in Functor_or_Operator hierarchy
You need to implement N*M definitions of how the every operation from Functor_or_Operator works on every class in A hierarchy.
The big thing is, you can do it without changing the interface of the class 'A'.
The declaration of the class 'A' becomes very stable in the case of the new additions when introducing new operations or functions working with objects of A hierarchy
or in case of new derived classes in the A hierarchy.
The stability of A (no changes to A) in the presence of additions is important to avoid costly (and sometimes impossible) recompilation of software which includes headers of A on many places.
For every new class in the A hierarchy, you extend the definition of base Functor_or_Operator, You add new implementation files, but you never need to touch the header of base class A (usually interface or abstract class).
class Functor_or_Operator
{
virtual void apply(A*)=0;
virtual void apply(B*)=0;
virtual void apply(C*)=0;
}
void A::apply(Functor_or_Operator* f)
{ f->apply(this);} //you need this only if A is not abstract (it is instantiable)
class B:public A
{
public:
void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymhorphic Functor f on this object
//..the rest of B implementation.
}
class C:public A
{
public:
void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymorfic Functor f on this object
//..the rest of C implementation.
}
class Functor_or_Operator_1:public Functor_or_Operator
{
public:
//implementations of application of a function represented by Functor_or_Operator_1 on each A,B,C
void apply(A*) {}//( only if A is instantiable,not an abstract class)
void apply(B*) {}
void apply(C*) {}
}
class Functor_or_Operator_2:public Functor_or_Operator
{
public:
//implementations of application of a function represented by Functor_or_Operator_2 on each A,B,C
void apply(A*) {}//( only if A is instantiable,not an abstract class)
void apply(B*) {}
void apply(C*) {}
}