Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Visitor pattern
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Examples == === C# === This example declares a separate <code>ExpressionPrintingVisitor</code> class that takes care of the printing. If the introduction of a new concrete visitor is desired, a new class will be created to implement the Visitor interface, and new implementations for the Visit methods will be provided. The existing classes (Literal and Addition) will remain unchanged. <syntaxhighlight lang="csharp"> using System; namespace Wikipedia; public interface Visitor { void Visit(Literal literal); void Visit(Addition addition); } public class ExpressionPrintingVisitor : Visitor { public void Visit(Literal literal) { Console.WriteLine(literal.Value); } public void Visit(Addition addition) { double leftValue = addition.Left.GetValue(); double rightValue = addition.Right.GetValue(); var sum = addition.GetValue(); Console.WriteLine($"{leftValue} + {rightValue} = {sum}"); } } public abstract class Expression { public abstract void Accept(Visitor v); public abstract double GetValue(); } public class Literal : Expression { public Literal(double value) { this.Value = value; } public double Value { get; set; } public override void Accept(Visitor v) { v.Visit(this); } public override double GetValue() { return Value; } } public class Addition : Expression { public Addition(Expression left, Expression right) { Left = left; Right = right; } public Expression Left { get; set; } public Expression Right { get; set; } public override void Accept(Visitor v) { Left.Accept(v); Right.Accept(v); v.Visit(this); } public override double GetValue() { return Left.GetValue() + Right.GetValue(); } } public static class Program { public static void Main(string[] args) { // Emulate 1 + 2 + 3 var e = new Addition( new Addition( new Literal(1), new Literal(2) ), new Literal(3) ); var printingVisitor = new ExpressionPrintingVisitor(); e.Accept(printingVisitor); Console.ReadKey(); } } </syntaxhighlight> === Smalltalk === <!-- There must be an Smalltalk example because it was Dan Ingalls who first described double dispatch in Smalltalk: Daniel H. H. Ingalls. A Simple Technique for Handling Multiple Polymorphism. In Proceedings of OOPSLA '86, Object–Oriented Programming Systems, Languages and Applications, pages 347–349, November 1986. Printed as SIGPLAN Notices, 21(11). --> In this case, it is the object's responsibility to know how to print itself on a stream. The visitor here is then the object, not the stream. <syntaxhighlight lang="smalltalk"> "There's no syntax for creating a class. Classes are created by sending messages to other classes." WriteStream subclass: #ExpressionPrinter instanceVariableNames: '' classVariableNames: '' package: 'Wikipedia'. ExpressionPrinter>>write: anObject "Delegates the action to the object. The object doesn't need to be of any special class; it only needs to be able to understand the message #putOn:" anObject putOn: self. ^ anObject. Object subclass: #Expression instanceVariableNames: '' classVariableNames: '' package: 'Wikipedia'. Expression subclass: #Literal instanceVariableNames: 'value' classVariableNames: '' package: 'Wikipedia'. Literal class>>with: aValue "Class method for building an instance of the Literal class" ^ self new value: aValue; yourself. Literal>>value: aValue "Setter for value" value := aValue. Literal>>putOn: aStream "A Literal object knows how to print itself" aStream nextPutAll: value asString. Expression subclass: #Addition instanceVariableNames: 'left right' classVariableNames: '' package: 'Wikipedia'. Addition class>>left: a right: b "Class method for building an instance of the Addition class" ^ self new left: a; right: b; yourself. Addition>>left: anExpression "Setter for left" left := anExpression. Addition>>right: anExpression "Setter for right" right := anExpression. Addition>>putOn: aStream "An Addition object knows how to print itself" aStream nextPut: $(. left putOn: aStream. aStream nextPut: $+. right putOn: aStream. aStream nextPut: $). Object subclass: #Program instanceVariableNames: '' classVariableNames: '' package: 'Wikipedia'. Program>>main | expression stream | expression := Addition left: (Addition left: (Literal with: 1) right: (Literal with: 2)) right: (Literal with: 3). stream := ExpressionPrinter on: (String new: 100). stream write: expression. Transcript show: stream contents. Transcript flush. </syntaxhighlight> <!-- This article exists to explain a design pattern, not to show how it interacts with the subtleties of many languages. Wikipedia is not a list of examples, but there must be a C++ one. Add no examples from other programming languages here. Instead, add them to: http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Visitor --> === Go === Go does not support method overloading, so the visit methods need different names. A typical visitor interface might be <syntaxhighlight lang="go"> type Visitor interface { visitWheel(wheel Wheel) string visitEngine(engine Engine) string visitBody(body Body) string visitCar(car Car) string } </syntaxhighlight> === Java === <!-- This article exists to explain a design pattern, not to show how it interacts with the subtleties of many languages. Wikipedia is not a list of examples. Add no examples from other programming languages here. Instead, add them to: http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Visitor --> The following example is in the language [[Java (programming language)|Java]], and shows how the contents of a tree of nodes (in this case describing the components of a car) can be printed. Instead of creating <code>print</code> methods for each node subclass (<code>Wheel</code>, <code>Engine</code>, <code>Body</code>, and <code>Car</code>), one visitor class (<code>CarElementPrintVisitor</code>) performs the required printing action. Because different node subclasses require slightly different actions to print properly, <code>CarElementPrintVisitor</code> dispatches actions based on the class of the argument passed to its <code>visit</code> method. <code>CarElementDoVisitor</code>, which is analogous to a save operation for a different file format, does likewise. ==== Diagram ==== [[File:UML diagram of an example of the Visitor design pattern.png|UML diagram of the Visitor pattern example with Car Elements]] ==== Sources ==== <syntaxhighlight lang=Java> import java.util.List; interface CarElement { void accept(CarElementVisitor visitor); } interface CarElementVisitor { void visit(Body body); void visit(Car car); void visit(Engine engine); void visit(Wheel wheel); } class Wheel implements CarElement { private final String name; public Wheel(final String name) { this.name = name; } public String getName() { return name; } @Override public void accept(CarElementVisitor visitor) { /* * accept(CarElementVisitor) in Wheel implements * accept(CarElementVisitor) in CarElement, so the call * to accept is bound at run time. This can be considered * the *first* dispatch. However, the decision to call * visit(Wheel) (as opposed to visit(Engine) etc.) can be * made during compile time since 'this' is known at compile * time to be a Wheel. Moreover, each implementation of * CarElementVisitor implements the visit(Wheel), which is * another decision that is made at run time. This can be * considered the *second* dispatch. */ visitor.visit(this); } } class Body implements CarElement { @Override public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Engine implements CarElement { @Override public void accept(CarElementVisitor visitor) { visitor.visit(this); } } 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()); } } </syntaxhighlight> <!-- This article exists to explain a design pattern, not to show how it interacts with the subtleties of many languages. Wikipedia is not a list of examples. Add no examples from other programming languages here. Instead, add them to: http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Visitor --> ==== Output ==== <pre> 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 </pre> === Common Lisp === ==== Sources ==== <syntaxhighlight lang=Lisp>(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 :name "rear-right-wheel") ,(make-instance 'body :name "body") ,(make-instance 'engine :name "engine"))))) ;; traverse to print elements ;; stream *standard-output* plays the role of other-object here (traverse #'print a *standard-output*) (terpri) ;; print newline ;; traverse with arbitrary context from other object (traverse #'do-something a 42) ;; traverse with arbitrary context from other object (traverse #'do-something a 'abc))</syntaxhighlight> ==== Output ==== <pre>"front-left-wheel" "front-right-wheel" "rear-left-wheel" "rear-right-wheel" "body" "engine" kicking wheel "front-left-wheel" 42 times kicking wheel "front-right-wheel" 42 times kicking wheel "rear-left-wheel" 42 times kicking wheel "rear-right-wheel" 42 times don't know how "body" and 42 should interact starting engine "engine" 42 times kicking wheel "front-left-wheel" symbolically using symbol ABC kicking wheel "front-right-wheel" symbolically using symbol ABC kicking wheel "rear-left-wheel" symbolically using symbol ABC kicking wheel "rear-right-wheel" symbolically using symbol ABC don't know how "body" and ABC should interact starting engine "engine" symbolically using symbol ABC</pre> ==== Notes ==== The <code>other-object</code> parameter is superfluous in <code>traverse</code>. The reason is that it is possible to use an anonymous function that calls the desired target method with a lexically captured object: <syntaxhighlight lang=Lisp>(defmethod traverse (function (a auto)) ;; other-object removed (with-slots (elements) a (dolist (e elements) (funcall function e)))) ;; from here too ;; ... ;; alternative way to print-traverse (traverse (lambda (o) (print o *standard-output*)) a) ;; alternative way to do-something with ;; elements of a and integer 42 (traverse (lambda (o) (do-something o 42)) a)</syntaxhighlight> Now, the multiple dispatch occurs in the call issued from the body of the anonymous function, and so <code>traverse</code> is just a mapping function that distributes a function application over the elements of an object. Thus all traces of the Visitor Pattern disappear, except for the mapping function, in which there is no evidence of two objects being involved. All knowledge of there being two objects and a dispatch on their types is in the lambda function. === Python === Python does not support method overloading in the classical sense (polymorphic behavior according to type of passed parameters), so the "visit" methods for the different model types need to have different names. ==== Sources ==== <syntaxhighlight lang="python"> """ Visitor pattern example. """ from abc import ABCMeta, abstractmethod NOT_IMPLEMENTED = "You should implement this." class CarElement(metaclass=ABCMeta): @abstractmethod def accept(self, visitor): raise NotImplementedError(NOT_IMPLEMENTED) class Body(CarElement): def accept(self, visitor): visitor.visitBody(self) class Engine(CarElement): def accept(self, visitor): visitor.visitEngine(self) class Wheel(CarElement): def __init__(self, name): self.name = name def accept(self, visitor): visitor.visitWheel(self) class Car(CarElement): def __init__(self): self.elements = [ Wheel("front left"), Wheel("front right"), Wheel("back left"), Wheel("back right"), Body(), Engine() ] def accept(self, visitor): for element in self.elements: element.accept(visitor) visitor.visitCar(self) class CarElementVisitor(metaclass=ABCMeta): @abstractmethod def visitBody(self, element): raise NotImplementedError(NOT_IMPLEMENTED) @abstractmethod def visitEngine(self, element): raise NotImplementedError(NOT_IMPLEMENTED) @abstractmethod def visitWheel(self, element): raise NotImplementedError(NOT_IMPLEMENTED) @abstractmethod def visitCar(self, element): raise NotImplementedError(NOT_IMPLEMENTED) class CarElementDoVisitor(CarElementVisitor): def visitBody(self, body): print("Moving my body.") def visitCar(self, car): print("Starting my car.") def visitWheel(self, wheel): print("Kicking my {} wheel.".format(wheel.name)) def visitEngine(self, engine): print("Starting my engine.") class CarElementPrintVisitor(CarElementVisitor): def visitBody(self, body): print("Visiting body.") def visitCar(self, car): print("Visiting car.") def visitWheel(self, wheel): print("Visiting {} wheel.".format(wheel.name)) def visitEngine(self, engine): print("Visiting engine.") car = Car() car.accept(CarElementPrintVisitor()) car.accept(CarElementDoVisitor()) </syntaxhighlight> ==== Output ==== <syntaxhighlight lang="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. </syntaxhighlight> ==== Abstraction ==== Using Python 3 or above allows to make a general implementation of the accept method: <syntaxhighlight lang="python"> class Visitable: def accept(self, visitor): lookup = "visit_" + self.__qualname__.replace(".", "_") return getattr(visitor, lookup)(self) </syntaxhighlight> One could extend this to iterate over the class's method resolution order if they would like to fall back on already-implemented classes. They could also use the subclass hook feature to define the lookup in advance.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)