Visitor

Intent

Represent operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Class diagram of the original GoF pattern

structure-GoF:visitor

Improvement in MixJuice (1)

Solved Problem(s)

Information hiding problem
The fields of object structure tends to be public. (This problem is mentioned at p.337, line.1-4 in the GoF book.)

Used programming technique(s)

Separation of specifications and implementations of ConcreteElement classes. (This improvement is applicable also to another solution described below.)

Consequences

Structure and pseudo code

structure:visitor_sample1

module element {
  define abstract class Element {
    define abstract void accept(Visitor visitor);
  }
  define class ConcreteElementA extends Element {
    void accept(Visitor v){ v.visitConcreteElementA(this); }
  }
  define class ConcreteElementB extends Element {
    void accept(Visitor v){ v.visitConcreteElementB(this); }
  }
  define abstract class Visitor {
    define abstract void visitConcreteElementA(ConcreteElementA a);
    define abstract void visitConcreteElementB(ConcreteElementB a);
  }
}
module element.implementation extends element {
  class ConcreteElementA {
    int state;
  }
  class ConcreteElementB {
    int state;
  }
}
module visitor extends element {
  define class ConcreteVisitor extends Visitor {}
}
module visitor.implementation
  extends visitor, element.implementation {
  class ConcreteVisitor {
    void visitConcreteElementA(ConcreteElementA a){
      ... int x = a.state; ...
    }
    void visitConcreteElementB(ConcreteElementB b){
      ... int x = b.state; ...
    }
  }
}

Improvement in MixJuice (2)

Solved Problem(s)

Introduction problem
Introducing Visitor pattern to existing object structure is impossible without modifying the source code of object structure. (This problem is not mentioned in the GoF book.)
Extensibility problem
Adding new ConcreteElement classes is impossible without modifying the source code of Visitor and ConcreteVisitor classes. (This problem is mentioned at p.336, line.4-17 in the GoF book.)

Used programming technique(s)

Abstract method addition to Element and ConcreteElement classes solves the introductionability problem. Abstract method addition to Visitor and ConcreteVisitor classes solves the extensibility problem.

Consequences

Structure and pseudo code

structure:visitor_sample2

module element {
  define abstract class Element {...}
  define class ConcreteElementA extends Element {...}
  define class ConcreteElementB extends Element {...}
}

module visitor extends element {
  class Element { define abstract void accept(Visitor v); }
  class ConcreteElementA { void accept(Visitor v) { v.visit(this); } }
  class ConcreteElementB { void accept(Visitor v) { v.visit(this); } }

  define class Visitor {
    define abstract void visit(ConcreteElementA elt);
    define abstract void visit(ConcreteElementB elt);
  }

  define class ConcreteVisitor1 extends Visitor {
    void visit(ConcreteElementA elt) {...}
    void visit(ConcreteElementB elt) {...}
  }

  define class ConcreteVisitor1a extends ConcreteVisitor1 {
    void visit(ConcreteElementA elt) {...}
    void visit(ConcreteElementB elt) {...}
  }
}

module new_concrete_element extends visitor {
  define class ConcreteElementC extends Element {
    ...
    void accept(Visitor v) { v.visit(this); }
  }

  class Visitor {
    define abstract void visit(ConcreteElementC elt);
  }

  class ConcreteVisitor1 {
    void visit(ConcreteElementC elt) {...}
  }

  class ConcreteVisitor1a {
    void visit(ConcreteElementC elt) {...}
  }
}

Another solution in MixJuice:

Solved Problem(s)

Complexity problem
The class structure of Visitor pattern is complicated and error prone. (This problem is not mentioned in the GoF book.)

Used programming technique(s)

Abstract method addition to the existing object structure.

Consequences

Structure and pseudo code

structure:visitor_sample3

module element {
  define abstract class Element {...}
  define class ConcreteElementA extends Element {...}
  define class ConcreteElementB extends Element {...}
}

module traverser extends element {
  class Element { define abstract void traverse(); }
  class ConcreteElementA { void traverse() {...} }
  class ConcreteElementB { void traverse() {...} }
}

Akira TANAKA <akr@m17n.org>, Yuuji ICHISUGI <y-ichisugi@aist.go.jp>

Top