Visitor Pattern
In this pattern we make a class independent of the operations that
can be performed upon it. The operations are then defined within
their own separate Visitor classes. The class, or classes, upon which
they can operate (Elements) are made "visitor ready" so
that they can accept the Visitors.
The Visitor pattern can provide the following benefits:
a new operation can be provided without having to change all
of the affected Element classes. All we need to do is create a new
Visitor class.
all of the program logic for a specific operation is gathered
together into it's own Visitor class, avoiding a situation where the
operation logic is spread across each of the individual Element
classes that the operation can affect.
The pattern is especially applicable in the following situations:
where the Element classes are beyond the control of the
Programmer who will be tasked with adding, or changing, operations
that will act upon the Element classes.
where the application will have multiple Element classes with
differing interfaces, and there is the need to perform the same
operations upon all of the Element objects, where the operation
algorithms need to be different due to the differences in Element
classes being operated upon.
where we can achieve code sharing or improved organisation of
our program logic, by gathering together the code required for an
operation that will be performed upon a diverse set of Element
classes.
where we expect that we will be more likely to add further,
or change existing, operations, than we will be to add further
Element classes to be operated upon.
A Visitor may operate upon a individual Element objects, or it may
operate upon a Composite collection of Element objects. The Visitor
may accumulate information, pertaining to the collection as a whole,
as it iterates through all of the member Elements. This is similar in
function to an Internal Iterator (see Iterator pattern in the links
below), however the Visitor pattern doesn't require that each of the
Element objects that it will navigate through share a common base
class or interface.
The Visitor pattern has a couple of potential problems:
we may be forced to compromise encapsulation, by needing to
expose too much of the Element class's internals to make the Element
classes "visitor ready"
it requires more source code changes if we need to add a new
Element class where there are a lot of Visitor classes that will be
required to operate upon it.
if overused it can increase undesirable coupling within our
application, versus a solution where we just used polymorphism; ie.
the Elements descend from an Abstract base class, and each Element
overriding the operation" methods.
I have two illustrations of the Visitor pattern:
the first example has two Element classes, and two Visitor
operations to act upon those Elements.
the second example shows a Visitor acting upon a composite
object containing a mixed collection of Element objects. It operates
upon the composite, and then provides statistics about the whole
collection.
Here is the client code to run the first illustration:
/* Construct two Element objects. They inherit from the
* same base class, but are of different types. Their
* shared base class is "visitor ready", and has a readonly
* Value property. Set their Value property by their
* differing mechanisms to the values "Microsoft" and
* "Hejlsberg". */
ElementBase element = new ConcreteElement_1("Microsoft");
ElementBase element2 = new ConcreteElement_2();
(ConcreteElement_2)element2).Name = "Hejlsberg";
ShowUserCommentary(1);
ShowContentsOfValueProperty(element.Value);
ShowContentsOfValueProperty(element2.Value);
/* Create 2 Visitor objects. One can cause the target
* Element's Value property contents to be converted to
* upper case, and the other can cause the characters in
* the properties contents to become separated by the "_"
* character. */
VisitorBase vCapitalise = new ConcreteVistor_1();
VisitorBase vAddDashes = new ConcreteVistor_2();
/* Apply the one Visitor to the 1st Element, and both
* Visitors the 2nd Element. */
element.Accept(vAddDashes);
element2.Accept(vCapitalise);
element2.Accept(vAddDashes);
ShowUserCommentary(2);
ShowContentsOfValueProperty(element.Value);
ShowContentsOfValueProperty(element2.Value);
And this is the output:

The essential interface for the visitor pattern can be thought as
as:
// --- interfaces
public interface IElementBase {
void Accept(IVisitorbase v)
}
public interface IVisitorBase {
}
The Visitor is passed into the Element's Accept method. The concrete
Element class that receives the Accept method call will pass itself
into the method within the Visitor object that specifically handles
this flavour of Element concrete class as we are about to see. Here
is the definition of the base class for the Element classes. The
property is just something I need for the demonstration. The key
thing is the Accept method, which is what is making the Element
classes "visitor ready".
// Element; objects that get acted upon by the Visitors
public abstract class ElementBase {
// fields
protected string _value;
// properties
public string Value {
get {return _value;}
}
// methods
// ... method to make the Element visitor-ready
abstract public void Accept(VisitorBase visitor);
}
Next we shall look at the concrete Element implementations. The key
part to focus upon is the overridden Accept methods. The incoming
Visitor will have a separate method for each concrete Element class.
The overridden Accept method calls the Visitor method that
specifically handles this operation for this specific concrete
Element class.
The other source code is just something to make the point that
each of the concrete classes can have differing interfaces and
mechanisms.
public class ConcreteElement_1: ElementBase {
// fields
protected string _text;
// properties
public string Text {
get {return _text;}
set {
_text = value;
_value = value;
}
}
// constructor
public ConcreteElement_1 (string aText) {
this.Text = aText;
}
// methods
override public void Accept(VisitorBase visitor) {
visitor.VisitElement_1(this);
}
}
public class ConcreteElement_2: ElementBase {
// fields
private string _name;
// properties
public string Name {
get {return _name;}
set {
_name = value;
_value = value;
}
}
// methods
override public void Accept(VisitorBase visitor) {
visitor.VisitElement_2(this);
}
}
Next the definition of a base class for the Visitor classes. We have
abstract method definitions for each concrete Element class so the
compiler can check for us that each Visitor has been configured to
handle all of the concrete Element classes.
// --- Visitors; objects that will act upon upon the Elements
public abstract class VisitorBase {
// methods
public abstract void VisitElement_1(ConcreteElement_1 element);
public abstract void VisitElement_2(ConcreteElement_2 element);
}
Finally we have the Concrete Visitors which do all of the work. As we
can see the pattern relies up the fact that the Element classes have
exposed enough of their own state to allow the Visitor to achieve
it's objective. This exposure requirement can mean that the visitor
pattern is unsuitable for our application. This could occur if we
required so much exposure of the Element's internal state to the
point where we felt that the Element class's encapsulation had been
compromised.
public class ConcreteVistor_1 : VisitorBase {
// methods
override public void VisitElement_1(ConcreteElement_1 element) {
element.Text = element.Text.ToUpper();
}
override public void VisitElement_2(ConcreteElement_2 element) {
element.Name = element.Name.ToUpper();
}
}
public class ConcreteVistor_2 : VisitorBase {
// methods
override public void VisitElement_1(ConcreteElement_1 element) {
element.Text = FormatText(element.Text);
}
override public void VisitElement_2(ConcreteElement_2 element) {
element.Name = FormatText(element.Name);
}
private string FormatText(string aText) {
StringBuilder retval = new StringBuilder();
char[] arr;
arr = aText.ToCharArray();
foreach (char ch in arr) {
retval.Append(ch);
retval.Append('_');
}
if (retval.Length > 0)
retval.Remove(retval.Length-1,1);
return retval.ToString();
}
}
Visitor pattern – second illustration
In the first illustration we looked at a Visitor being applied to
an individual object, this time we will look at the Visitor being
dappled to a composite collection of diverse Element types. When our
Visitor is acting upon a collection we have the option of
accumulating state within the Visitor while it navigates through all
the Elements in the collection as we will see in this example.
The collection itself is an implementation of the Composite
pattern. This pattern is covered in my article upon the GOF's
"Structural Patterns"; see link at the
bottom of this article.
In my illustration the concrete Elements classes are various types
of fruits. The collection is a fruit bowl that can contain a number
of pieces of various types of fruit. Each piece of fruit has a
designated weight. We have a "juice" operation that will
convert the bowl of fruit into fruit juice. Each fruit type
has an assumed percentage juice yield based upon the amount of juice
to be expected from a piece of fruit of that type. The weight of
juice that is expected from the fruit bowl is therefore determined by
the fruit types, and the individual weights of the pieces of fruit.
Here is the snippet of client code, and the private method that it
uses to display the results:
/* Try a different implementation. This time we have a
* Composite class to contain a collection of Element
* classes. The Elements are fruit of various types
* and weights. */
FruitCollection fruitBowl = new FruitCollection();
fruitBowl.Add(new Apple(1.2f));
fruitBowl.Add(new Orange(1.4f));
fruitBowl.Add(new Apple(1.0f));
/* Create a Visitor. It converts the fruit to juice, and
* calculates the accumulated juice yield (weight) for
* fruit objects that it operates upon. Differing fruit
* types may have differing yield percentages. The point
* is to show a visitor acting upon a collection, and
* accumulating state during it's journey. */
ShowUserCommentary(3);
Juice juice = new Juice();
/* Apply the visitor to the collection; convert the fruit
* bowl into juice. */.
fruitBowl.Accept(juice);
ShowJuiceStats(juice);
/* Add another Element to the collection, reapply the
* Visitor to get a different result. */
ShowUserCommentary(4);
fruitBowl.Add(new Orange(0.8f));
juice.Reset();
fruitBowl.Accept(juice);
ShowJuiceStatistics(juice);
}
private void ShowJuiceStats(Juice juiceVisitor { listBox1.AppendText(String.Format(
"\n Juice yield weight is {0:0.#}",
juiceVisitor.YieldWeight));
listBox1.AppendText(String.Format(
"\n Percentage apple juice = {0:0.#}",
juiceVisitor.PercentageApple));
}
Here is the output:

Here is the implementation of the base class for the fruit
Elements. The pattern doesn't require that our Element classes share
a common base class, although I have one in this illustration. The
pattern only requires that the Element classes implement an interface
containing the Accept method.
// --- Base class for the "Element" class in the pattern
abstract public class FruitBase {
// fields
private float _weight;
// properties
public float Weight {
get {return _weight;}
}
// constructor
public FruitBase(float aWeight) {
_weight = aWeight;
}
// methods
// ... method to make the Element visitor-ready
abstract public void Accept(Juice visitor);
public void ResetWeight() {
_weight = 0;
}
}
Next is the implementation of the Composite class for the bowl of
fruit. As you can see it implements it's own "Accept"
method, which iterates through the collection's member Elements, and
calling the Accept method for each.
// --- Collection of the "Element" objects
public class FruitCollection {
// fields
private List<FruitBase > _collection =
new List<FruitBase >();
// methods
public void Add(FruitBase aFruit) {
_collection.Add(aFruit);
}
public void Remove(FruitBase aFruit) {
_collection.Remove(aFruit);
}
public void Accept(Juice visitor) {
foreach (FruitBase fruit in _collection) {
fruit.Accept(visitor);
}
}
}
Next the concrete Element classes:
// --- Concrete "Element" classes
public class Apple: FruitBase {
// constructor
public Apple(float aWeight) :base(aWeight) {
}
// methods
override public void Accept(Juice visitor) {
visitor.VisitApple(this);
}
}
public class Orange: FruitBase {
// constructor
public Orange(float aWeight) :base(aWeight) {
}
// methods
override public void Accept(Juice visitor) {
visitor.VisitOrange(this);
}
}
Finally the implementation of the Visitor class. It contains the
"juice" methods for each Element class type, and also the
mechanisms for accumulating and returning state values.
// --- Concrete "Visitor" class
public class Juice {
// fields
protected float _weightApples, _weightOranges;
// properties
public float PercentageApple {
get {return
(_weightApples * 100)/(_weightApples
+ _weightOranges) ;}
}
public float YieldWeight {
get {return (_weightApples + _weightOranges) ;}
}
// methods
public void VisitApple(Apple fruit) {
_weightApples += fruit.Weight * .85f;
}
public void VisitOrange(Orange fruit) {
_weightOranges
+= fruit.Weight * .75f; // thick skin, less yield
}
public void Reset() {
_weightApples = 0;
_weightOranges = 0;
}
} |