Visitor pattern |
In object-oriented programming and software engineering, the visitor design pattern (computer science) is a way of separating an Algorithm from an object structure. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures.
The idea is to use a structure of element classes, each of which has an accept method that takes a visitor object as an argument. The visitor is an interface that has a different visit() method for each element class. The accept() method of an element class calls back the visit() method for its class. Separate concrete visitor classes can then be written that perform some particular operations.
One of these visit() methods of a concrete visitor can be thought of as methods not of a single class, but rather methods of a pair of classes: the concrete visitor and the particular element class. Thus the visitor pattern simulates double dispatch in a conventional single-dispatch object-oriented language such as Java programming language, Smalltalk, and C plus plus. For an explanation of how double dispatch differs from function overloading, see Double dispatch#Double dispatch is more than function overloading in the double dispatch article.
The visitor pattern also specifies how iteration occurs over the object structure. In the simplest version, where each algorithm needs to iterate in the same way, the accept() method of a container element, in addition to calling back the visit() method of the visitor, also passes the visitor object to the accept() method of all its constituent child elements.
Because the Visitor object has one principal function (manifested in a plurality of specialized methods) and that function is called visit(), the Visitor can be readily identified as a potential function object or functor. Likewise, the accept() function can be identified as a function applicator, a mapper, which knows how to traverse a particular type of object and apply a function to its elements. The Common Lisp example later in this page shows an implementation of the same behavior as the other examples, using functions. It s noteworthy that although Common Lisp has one of the few object systems that support multiple dispatch, the first part of the example does not rely on multiple dispatch. The use of multiple dispatch is introduced in a second example; yet the framework remains the same. Lisp s object system with its multiple dispatch does not replace the Visitor pattern, but merely provides a more concise implementation of it in which the pattern all but disappears.
=Examples=
==Perl==
The following example uses the Perl programming language:
package Wheel;
# class for storing information about a Wheel
use warnings; use strict; use Carp;
sub new { my $class = shift; my $name = shift; my $self = { NAME => $name, }; my $closure = sub { my $field = shift; if (@_) { $self->{$field} = shift; } return $self->{$field}; }; bless ($closure,$class); return $closure; }
# public accessors sub name { &{ $_[0] }( NAME , @_[1 .. $#_]) }
sub accept { my $self = shift; my $visitor = shift; $visitor->visitWheel($self); }
1; package Body;
# class for storing information about a Body
use warnings; use strict; use Carp;
sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } sub accept { my $self = shift; my $visitor = shift; $visitor->visitBody($self); }
1; package Engine;
# class for storing information about an Engine
use warnings; use strict; use Carp;
sub new { my $class = shift; my $self = {}; bless $self,$class; return $self; } sub accept { my $self = shift; my $visitor = shift; $visitor->visitEngine($self); }
1; package Car;
# class for storing information about a Car
use warnings; use strict; use Carp;
sub new { my $class = shift; my $self = { ENGINE => undef, BODY => undef, WHEELS => undef, # a list of wheels }; my $closure = sub { my $field = shift; if (@_) { $self->{$field} = shift; } return $self->{$field}; }; bless ($closure,$class); return $closure; }
# public accessors sub engine { &{ $_[0] }( ENGINE , @_[1 .. $#_]) } sub body { &{ $_[0] }( BODY , @_[1 .. $#_]) } sub wheels { &{ $_[0] }( WHEELS , @_[1 .. $#_]) }
sub accept { my $self = shift; my $visitor = shift; $visitor->visitCar($self); $self->engine->accept($visitor); $self->body->accept($visitor); map { $_->accept($visitor) } @{$self->wheels}; }
1; package PrintVisitor;
# class for grouping together all the different print messages for car parts
use warnings; use strict; use Carp;
sub new { my $class = shift; my $self = {}; bless $self,$class; return $self; }
sub visitWheel { my $self = shift; my $wheel = shift; print Visiting . $wheel->name . wheel ; } sub visitEngine { my $self = shift; my $engine = shift; print Visiting engine ; } sub visitBody { my $self = shift; my $body = shift; print Visiting body ; } sub visitCar { my $self = shift; my $car = shift; print Visiting car ; }
1; #!/usr/bin/perl
# Using the visitor class
use strict; use warnings;
use Car; use PrintVisitor; use Wheel; use Body; use Engine;
my $car = Car->new(); $car->engine( Engine->new() ); $car->body( Body->new() ); $car->wheels( [Wheel->new( front left ), Wheel->new( front right ), Wheel->new( back left ), Wheel->new( back right )] ); my $visitor = PrintVisitor->new(); $car->accept($visitor);
==Python==
The following example uses the Python programming language:
class Wheel: def __init__(self,name): self.name = name def accept(self,visitor): visitor.visitWheel(self)
class Engine: def accept(self,visitor): visitor.visitEngine(self)
class Body: def accept(self,visitor): visitor.visitBody(self)
class Car: def __init__(self): self.engine = Engine() self.body = Body() self.wheels = [ Wheel( front left ), Wheel( front right ), Wheel( back left ) , Wheel( back right ) ] def accept(self,visitor): visitor.visitCar(self) self.engine.accept( visitor ) self.body.accept( visitor ) for wheel in self.wheels: wheel.accept( visitor )
class PrintVisitor: def visitWheel(self,wheel): print Visiting +wheel.name+ wheel def visitEngine(self,engine): print Visiting engine def visitBody(self,body): print Visiting body def visitCar(self,car): print Visiting car
car = Car() visitor = PrintVisitor() car.accept(visitor)
==Java==
The following example uses the Java programming language:
interface Visitor { void visit(Wheel wheel); void visit(Engine engine); void visit(Body body); void visit(Car car); }
class Wheel { private String name; Wheel(String name) { this.name = name; } String getName() { return this.name; } void accept(Visitor visitor) { visitor.visit(this); } }
class Engine { void accept(Visitor visitor) { visitor.visit(this); } }
class Body { void accept(Visitor visitor) { visitor.visit(this); } }
class Car { private Engine engine = new Engine(); private Body body = new Body(); private Wheel[] wheels = { new Wheel( front left ), new Wheel( front right ), new Wheel( back left ) , new Wheel( back right ) }; void accept(Visitor visitor) { visitor.visit(this); engine.accept( visitor ); body.accept( visitor ); for(int i=0; ivisit(this); }
Wheel(std::string const& name_) : name(name_) { } };
class Engine { public: void accept(Visitor *visitor) { visitor->visit(this); } };
class Body { public: void accept(Visitor *visitor) { visitor->visit(this); } };
class Car { private: Engine *engine; Body *body; Wheel *wheels[4];
public: void accept(Visitor *visitor) { visitor->visit(this); engine->accept(visitor); body->accept(visitor); for (int i = 0; i < 4; i++) { wheels[i]->accept(visitor); } }
Car() : engine(new Engine()), body(new Body()) { wheels[0] = new Wheel( front left ); wheels[1] = new Wheel( front right ); wheels[2] = new Wheel( back left ); wheels[3] = new Wheel( back right ); }
~Car() { delete engine; delete body; for (int i = 0; i < 4; i++) { delete wheels[i]; } } };
class PrintVisitor : public Visitor { public: void visit(Wheel *wheel) { std::cout|
|
