class Car implements CarElement { private final List<CarElement> elements; public Car() { this.elements = List.of( new Wheel("front left"), new Wheel("front right"), new Wheel("back left"), new Wheel("back right"), new Body(), new Engine() ); } @Override public void accept(CarElementVisitor visitor) { for (CarElement element : elements) { element.accept(visitor); } visitor.visit(this); } } class CarElementDoVisitor implements CarElementVisitor { @Override public void visit(Body body) { System.out.println("Moving my body"); } @Override public void visit(Car car) { System.out.println("Starting my car"); } @Override public void visit(Wheel wheel) { System.out.println("Kicking my " + wheel.getName() + " wheel"); } @Override public void visit(Engine engine) { System.out.println("Starting my engine"); } } class CarElementPrintVisitor implements CarElementVisitor { @Override public void visit(Body body) { System.out.println("Visiting body"); } @Override public void visit(Car car) { System.out.println("Visiting car"); } @Override public void visit(Engine engine) { System.out.println("Visiting engine"); } @Override public void visit(Wheel wheel) { System.out.println("Visiting " + wheel.getName() + " wheel"); } } public class VisitorDemo { public static void main(final String[] args) { Car car = new Car(); car.accept(new CarElementPrintVisitor()); car.accept(new CarElementDoVisitor()); } } Output Visiting front left wheel Visiting front right wheel Visiting back left wheel Visiting back right wheel Visiting body Visiting engine Visiting car Kicking my front left wheel Kicking my front right wheel Kicking my back left wheel Kicking my back right wheel Moving my body Starting my engine Starting my car Common Lisp example Sources (defclass auto () ((elements :initarg :elements))) (defclass auto-part () ((name :initarg :name :initform "<unnamed-car-part>"))) (defmethod print-object ((p auto-part) stream) (print-object (slot-value p 'name) stream)) (defclass wheel (auto-part) ()) (defclass body (auto-part) ()) (defclass engine (auto-part) ()) (defgeneric traverse (function object other-object)) (defmethod traverse (function (a auto) other-object) (with-slots (elements) a (dolist (e elements) (funcall function e other-object)))) ;; do-something visitations ;; catch all (defmethod do-something (object other-object) (format t "don't know how ~s and ~s should interact~%" object other-object)) ;; visitation involving wheel and integer (defmethod do-something ((object wheel) (other-object integer)) (format t "kicking wheel ~s ~s times~%" object other-object)) ;; visitation involving wheel and symbol (defmethod do-something ((object wheel) (other-object symbol)) (format t "kicking wheel ~s symbolically using symbol ~s~%" object other-object)) (defmethod do-something ((object engine) (other-object integer)) (format t "starting engine ~s ~s times~%" object other-object)) (defmethod do-something ((object engine) (other-object symbol)) (format t "starting engine ~s symbolically using symbol ~s~%" object other-object)) (let ((a (make-instance 'auto :elements `(,(make-instance 'wheel :name "front-left-wheel") ,(make-instance 'wheel :name "front-right-wheel") ,(make-instance 'wheel :name "rear-left-wheel") ,(make-instance 'wheel