Computer Science Design Patterns/Visitor

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

Contents

[edit] Example in Java

The following example is in the Java programming language:

interface CarElementVisitor {
    void visit(Wheel wheel);
    void visit(Engine engine);
    void visit(Body body);
    void visitCar(Car car);
}
interface CarElement {
    void accept(CarElementVisitor visitor); // CarElements have to provide accept().
}
class Wheel implements CarElement {
    private String name;
    Wheel(String name) {
        this.name = name;
    }
    String getName() {
        return this.name;
    }
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Engine implements CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Body implements CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Car  {
    CarElement[] elements;
    public CarElement[] getElements() {
        return elements.clone(); // Return a copy of the array of references.
    }
    public Car() {
        this.elements = new CarElement[]
          { new Wheel("front left"), new Wheel("front right"),
            new Wheel("back left") , new Wheel("back right"),
            new Body(), new Engine() };
    }
}
 
class CarElementPrintVisitor implements CarElementVisitor {
    public void visit(Wheel wheel) {      
        System.out.println("Visiting "+ wheel.getName()
                            + " wheel");
    }
    public void visit(Engine engine) {
        System.out.println("Visiting engine");
    }
    public void visit(Body body) {
        System.out.println("Visiting body");
    }
 
    public void visitCar(Car car) {
        System.out.println("\nVisiting car");
        for(CarElement element : car.getElements()) {
            element.accept(this);
        }
        System.out.println("Visited car");
    }
}
 
class CarElementDoVisitor implements CarElementVisitor {
    public void visit(Wheel wheel) {
        System.out.println("Kicking my "+ wheel.getName());
    }
    public void visit(Engine engine) {
        System.out.println("Starting my engine");
    }
    public void visit(Body body) {
        System.out.println("Moving my body");
    }
    public void visitCar(Car car) {
        System.out.println("\nStarting my car");
        for(CarElement carElement : car.getElements()) {
            carElement.accept(this);
        }
        System.out.println("Started car");
    }
 
}
 
public class VisitorDemo {
    static public void main(String[] args){
        Car car = new Car();
        CarElementVisitor printVisitor = new CarElementPrintVisitor();
        CarElementVisitor doVisitor = new CarElementDoVisitor();
        printVisitor.visitCar(car);
        doVisitor.visitCar(car);
    }
}

[edit] Example in D

The following example is in the D programming language:

import std.stdio;
import std.string;
 
interface CarElementVisitor {
    void visit(Wheel wheel);
    void visit(Engine engine);
    void visit(Body bod);
    void visitCar(Car car);
}
 
interface CarElement{
    void accept(CarElementVisitor visitor);
}
 
class Wheel : CarElement {
    private string name;
    this(string name) {
        this.name = name;
    }
    string getName() {
        return name;
    }
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Engine : CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Body : CarElement {
    public void accept(CarElementVisitor visitor) {
        visitor.visit(this);
    }
}
 
class Car {
    CarElement[] elements;
    public CarElement[] getElements(){
        return elements;
    }
    public this() {
        elements =
        [
            cast(CarElement) new Wheel("front left"),
            cast(CarElement) new Wheel("front right"),
            cast(CarElement) new Wheel("back left"),
            cast(CarElement) new Wheel("back right"),
            cast(CarElement) new Body(),
            cast(CarElement) new Engine()
        ];
    }
}
 
class CarElementPrintVisitor : CarElementVisitor {
    public void visit(Wheel wheel) {
        writefln("Visiting "~ wheel.name ~ " wheel");
    }
    public void visit(Engine engine) {
        writefln("Visiting engine");
    }
    public void visit(Body bod) {
        writefln("Visiting body");
    }
    public void visitCar(Car car) {
        writefln("\nVisiting car");
        foreach(CarElement element ; car.elements) {
            element.accept(this);
        }
        writefln("Visited car");
    }
}
 
class CarElementDoVisitor : CarElementVisitor {
    public void visit(Wheel wheel) {
        writefln("Kicking my "~ wheel.name);
    }
    public void visit(Engine engine) {
        writefln("Starting my engine");
    }
    public void visit(Body bod) {
        writefln("Moving my body");
    }
    public void visitCar(Car car) {
        writefln("\nStarting my car");
        foreach(CarElement carElement ; car.getElements()) {
            carElement.accept(this);
        }
        writefln("Started car");
    }
}
 
void main(){
    Car car = new Car;
    CarElementVisitor printVisitor = new CarElementPrintVisitor;
    CarElementVisitor doVisitor = new CarElementDoVisitor;
    printVisitor.visitCar(car);
    doVisitor.visitCar(car);
}

[edit] Example in C++

The following example is an example in the C++ programming language:

#include <string>
#include <iostream>
#include <vector>
 
using namespace std;
 
class Wheel;
class Engine;
class Body;
class Car;
 
// interface to all car 'parts'
struct CarElementVisitor 
{
  virtual void visit(Wheel& wheel) const = 0;
  virtual void visit(Engine& engine) const = 0;
  virtual void visit(Body& body) const = 0;
 
  virtual void visitCar(Car& car) const = 0;
  virtual ~CarElementVisitor() {}
};
 
// interface to one part
struct CarElement 
{
  virtual void accept(const CarElementVisitor& visitor) = 0;
  virtual ~CarElement() {}
};
 
// wheel element, there are four wheels with unique names
class Wheel : public CarElement
{
public:
  explicit Wheel(const string& name) :
    name_(name)
  {
  }
  const string& getName() const 
  {
    return name_;
  }
  void accept(const CarElementVisitor& visitor)  
  {
    visitor.visit(*this);
  }
private:
    string name_;
};
 
// engine
class Engine : public CarElement
{
public:
  void accept(const CarElementVisitor& visitor) 
  {
    visitor.visit(*this);
  }
};
 
// body
class Body : public CarElement
{
public:
  void accept(const CarElementVisitor& visitor) 
  {
    visitor.visit(*this);
  }
};
 
// car, all car elements(parts) together
class Car 
{
public:
  vector<CarElement*>& getElements()
  {
    return elements_;
  }
  Car() 
  {
    // assume that neither push_back nor Wheel(const string&) may throw
    elements_.push_back( new Wheel("front left") );
    elements_.push_back( new Wheel("front right") );
    elements_.push_back( new Wheel("back left") );
    elements_.push_back( new Wheel("back right") );
    elements_.push_back( new Body() );
    elements_.push_back( new Engine() );
  }
  ~Car()
  {
    for(vector<CarElement*>::iterator it = elements_.begin(); 
      it != elements_.end(); ++it)
    {
      delete *it;
    }
  }
private:
  vector<CarElement*> elements_;
};
 
// PrintVisitor and DoVisitor show by using a different implementation the Car class is unchanged
// even though the algorithm is different in PrintVisitor and DoVisitor.
class CarElementPrintVisitor : public CarElementVisitor 
{
public:
  void visit(Wheel& wheel) const
  { 
    cout << "Visiting " << wheel.getName() << " wheel" << endl;
  }
  void visit(Engine& engine) const
  {
    cout << "Visiting engine" << endl;
  }
  void visit(Body& body) const
  {
    cout << "Visiting body" << endl;
  }
  void visitCar(Car& car) const
  {
    cout << endl << "Visiting car" << endl;
    vector<CarElement*>& elems = car.getElements();
    for(vector<CarElement*>::iterator it = elems.begin();
      it != elems.end(); ++it )
    {
      (*it)->accept(*this);	// this issues the callback i.e. to this from the element  
    }
    cout << "Visited car" << endl;
  }
};
 
class CarElementDoVisitor : public CarElementVisitor 
{
public:
  // these are specific implementations added to the original object without modifying the original struct
  void visit(Wheel& wheel) const
  {
    cout << "Kicking my " << wheel.getName() << " wheel" << endl;
  }
  void visit(Engine& engine) const
  {
    cout << "Starting my engine" << endl;
  }
  void visit(Body& body) const
  {
    cout << "Moving my body" << endl;
  }
  void visitCar(Car& car) const
  {
    cout << endl << "Starting my car" << endl;
    vector<CarElement*>& elems = car.getElements();
    for(vector<CarElement*>::iterator it = elems.begin();
      it != elems.end(); ++it )
    {
      (*it)->accept(*this);	// this issues the callback i.e. to this from the element  
    }
    cout << "Stopped car" << endl;
  }
};
 
int main()
{
  Car car;
  CarElementPrintVisitor printVisitor;
  CarElementDoVisitor doVisitor;
 
  printVisitor.visitCar(car);
  doVisitor.visitCar(car);
 
  return 0;
}

[edit] Example in C#

The following example is an example in the C# programming language:

using System;
 
namespace VistorPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var car = new Car();
            CarElementVisitor printVisitor = new CarElementPrintVisitor();
            CarElementVisitor doVisitor = new CarElementDoVisitor();
            printVisitor.visitCar(car);
            doVisitor.visitCar(car);
        }
    }
 
    public interface CarElementVisitor
    {
        void visit(Wheel wheel);
        void visit(Engine engine);
        void visit(Body body);
        void visitCar(Car car);
    }
    public interface CarElement
    {
        void accept(CarElementVisitor visitor); // CarElements have to provide accept().
    }
    public class Wheel : CarElement
    {
 
        public String name { get; set; }
 
        public void accept(CarElementVisitor visitor)
        {
            visitor.visit(this);
        }
    }
 
    public class Engine : CarElement
    {
        public void accept(CarElementVisitor visitor)
        {
            visitor.visit(this);
        }
    }
 
    public class Body : CarElement
    {
        public void accept(CarElementVisitor visitor)
        {
            visitor.visit(this);
        }
    }
 
    public class Car
    {
        public CarElement[] elements { get; private set; }
 
        public Car()
        {
            elements = new CarElement[]
          { new Wheel{name = "front left"}, new Wheel{name = "front right"},
            new Wheel{name = "back left"} , new Wheel{name="back right"},
            new Body(), new Engine() };
        }
    }
 
    public class CarElementPrintVisitor : CarElementVisitor
    {
        public void visit(Wheel wheel)
        {
            Console.WriteLine("Visiting " + wheel.name + " wheel");
        }
        public void visit(Engine engine)
        {
            Console.WriteLine("Visiting engine");
        }
        public void visit(Body body)
        {
            Console.WriteLine("Visiting body");
        }
 
        public void visitCar(Car car)
        {
            Console.WriteLine("\nVisiting car");
            foreach (var element in car.elements)
            {
                element.accept(this);
            }
            Console.WriteLine("Visited car");
        }
    }
 
    public class CarElementDoVisitor : CarElementVisitor
    {
        public void visit(Wheel wheel)
        {
            Console.WriteLine("Kicking my " + wheel.name);
        }
        public void visit(Engine engine)
        {
            Console.WriteLine("Starting my engine");
        }
        public void visit(Body body)
        {
            Console.WriteLine("Moving my body");
        }
        public void visitCar(Car car)
        {
            Console.WriteLine("\nStarting my car");
            foreach (var element in car.elements)
            {
                element.accept(this);
            }
        }
 
    }
}