Visitor pattern

Visitor pattern

[
LePUS3 ( [http://lepus.org.uk/ref/legend/legend.xml legend] ) ]

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure upon which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. Thus, using the visitor pattern helps conformance with the open/closed principle.

In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.

While powerful, the visitor pattern does have limitations as compared with conventional virtual functions. It is not possible to create visitors for objects without adding a small callback method inside each class and the callback method in each of the classes is not inheritable to the level of the new subclass.

Elaborated

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. Visitor is an interface that has a 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, by implementing these operations in their respective visit() methods.

One of these visit() methods of a concrete visitor can be thought of as a method not of a single class, but rather a method 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, Smalltalk, and C++. For an explanation of how double dispatch differs from function overloading, see Double dispatch is more than function overloading in the double dispatch article. In the Java language, two techniques have been documented which use reflection to simplify the mechanics of double dispatch simulation in the visitor pattern: [http://www.cs.ucla.edu/~palsberg/paper/compsac98.pdf getting rid of accept() methods] (the Walkabout variation), and [http://www.javaworld.com/javaworld/javatips/jw-javatip98.html getting rid of extra visit() methods] .

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. 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.

Example in Java

The following example is an example in the Java programming language:interface Visitor { void visit(Wheel wheel); void visit(Engine engine); void visit(Body body); void visitCar(Car car);}interface CarElement{ void accept(Visitor visitor);}class Wheel implements CarElement{ private String name; Wheel(String name) { this.name = name; } String getName() { return this.name; } public void accept(Visitor visitor) { visitor.visit(this); class Engine implements CarElement{ public void accept(Visitor visitor) { visitor.visit(this); class Body implements CarElement{ public void accept(Visitor visitor) { visitor.visit(this); class Car { CarElement [] elements; public CarElement [] getElements(){ return elements.clone(); } 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 PrintVisitor implements Visitor {

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(" Visiting car"); for(CarElement element : car.getElements()) { element.accept(this); } System.out.println("Visited car"); class DoVisitor implements Visitor { 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(" Starting 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(); Visitor printVisitor = new PrintVisitor(); Visitor doVisitor = new DoVisitor(); printVisitor.visitCar(car); doVisitor.visitCar(car);

Example in C++

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

using namespace std;

class Wheel;class Engine;class Body;class Car;

// interface to all car 'parts'struct Visitor { virtual void visit(Wheel& wheel) = 0; virtual void visit(Engine& engine) = 0; virtual void visit(Body& body) = 0; virtual void visitCar(Car& car) = 0;};

// interface to one partstruct CarElement { virtual void accept(Visitor &visitor) = 0;};

// wheel element, there are four wheels with unique nameclass Wheel : public CarElement{public: Wheel(const string &name) { _name = name; } string getName() { return _name; } void accept(Visitor& visitor) { visitor.visit(*this); }private: string _name;};

// engineclass Engine : public CarElement{public: void accept(Visitor& visitor) { visitor.visit(*this); ;

// bodyclass Body : public CarElement{public: void accept(Visitor& visitor) { visitor.visit(*this); ;

// car, all car elements(parts) togetherclass Car {public: list & getElements() { return elements; } Car() { 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() { while ( !elements.empty() ) { CarElement *p = *(elements.begin()); delete p; elements.erase( elements.begin() ); } }private: list elements;};

// PrintVisitor and DoVisitor show by using a different implementation the struct 'car' is unchanged// even though the algorithm is different in PrintVisitor and DoVisitor.class PrintVisitor : public Visitor {public: void visit(Wheel& wheel) { cout << "Visiting " << wheel.getName() << " wheel" << endl; } void visit(Engine& engine) { cout << "Visiting engine" << endl; } void visit(Body& body) { cout << "Visiting body" << endl; } void visitCar(Car& car) { cout << endl << "Visiting car" << endl; list & lst = car.getElements(); list::iterator it = lst.begin(); while ( it != lst.end() ) { (*it)->accept(*this); // this issues the callback i.e. to this from the element ++it; } cout << "Visited car" << endl; ; class DoVisitor : public Visitor {public: // these are specific implementations added to the original object without modifying the original struct void visit(Wheel& wheel) { cout << "Kicking my " << wheel.getName() << endl; } void visit(Engine& engine) { cout << "Starting my engine" << endl; } void visit(Body& body) { cout << "Moving my body" << endl; } void visitCar(Car& car) { cout << endl << "Starting my car" << endl; list & lst = car.getElements(); list::iterator it = lst.begin(); while ( it != lst.end() ) { (*it)->accept(*this); // this issues the callback i.e. to this from the element ++it; } cout << "Stopped car" << endl; ; int main(int argc, char* argv [] ){ Car car; Visitor* printVisitor( new PrintVisitor ); Visitor* doVisitor( new DoVisitor ); printVisitor->visitCar(car); doVisitor->visitCar(car); delete printVisitor; delete doVisitor; return 0;}

tate

Aside from potentially improving separation of concerns, the visitor pattern has an additional advantage over simply calling a polymorphic method: a visitor object can have state. This is extremely useful in many cases where the action performed on the object depends on previous such actions.

An example of this is a pretty-printer in a programming language implementation (such as a compiler or interpreter). Such a pretty-printer object (implemented as a visitor, in this example), will visit nodes in a data structure that represents a parsed and processed program. The pretty-printer will then generate a textual representation of the program tree. In order to make the representation human readable, the pretty-printer should properly indent program statements and expressions. The "current indentation level" can then be tracked by the visitor as its state, correctly applying encapsulation, whereas in a simple polymorphic method invocation, the indentation level would have to be exposed as a parameter and the caller would rely on the method implementation to use and propagate this parameter correctly.

ee also

*Double and multiple dispatch
*Composite pattern
*Hierarchical visitor pattern
*Strategy pattern
*Function object

External links

* [http://objectmentor.com/resources/articles/visitor.pdf The Visitor Family of Design Patterns] by Robert C. Martin - a rough chapter from "The Principles, Patterns, and Practices of Agile Software Development", Robert C. Martin, Prentice Hall
* [http://www.lepus.org.uk/ref/companion/Visitor.xml Visitor pattern in UML and in LePUS3] (a Design Description Language)
*Article " [http://se.ethz.ch/~meyer/publications/computer/visitor.pdf Componentization: the Visitor Example] by Bertrand Meyer and Karine Arnout, "Computer" (IEEE), vol. 39, no. 7, July 2006, pages 23-30.
*Article " [http://www.onjava.com/pub/a/onjava/2005/06/01/searchvisitor.html Domain Searching Using Visitors] " by Paul Mukherjee
*Article " [http://codeproject.com/cpp/ConditionInterpreter.asp Parsing Conditions using Interpreter and Visitor Pattern] "
*Article [http://www.cs.bham.ac.uk/~hxt/research/mfps-visitors.pdf A Type-theoretic Reconstruction of the Visitor Pattern]
*Article " [http://citeseer.ist.psu.edu/palsberg97essence.html The Essence of the Visitor Pattern] " by Jens Palsberg and C. Barry Jay. 1997 IEEE-CS COMPSAC paper showing that accept() methods are unnecessary when reflection is available; introduces term 'Walkabout' for the technique.
*Article " [http://www.polyglotinc.com/articles.html#reflectVisitor Eliminate accept() methods from your Visitor pattern] " by Bruce Wallace
*Article " [http://www.artima.com/cppsource/cooperative_visitor.html Cooperative Visitor: A Template Technique for Visitor Creation] " by Anand Shankar Krishnamoorthi
* [http://goblin.colourcountry.net/apt1002/Visitor%20patterns Visitor Patterns] as a universal model of terminating computation.
* [http://www.oodesign.com/oo_design_patterns/behavioral_patterns/visitor_pattern.html Visitor Pattern] using reflection(java).
* [http://perfectjpattern.sourceforge.net/dp-visitor.html PerfectJPattern Open Source Project] , Provides a context-free and type-safe implementation of the Visitor Pattern in Java based on Delegates.


Wikimedia Foundation. 2010.

Игры ⚽ Нужно сделать НИР?

Look at other dictionaries:

  • Visitor Pattern — Der Besucher (engl.: visitor bzw. visitor pattern) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung und gehört zu der Kategorie der Verhaltensmuster (Behavioural Patterns). Es dient zum Kapseln von Operationen, die auf Elementen… …   Deutsch Wikipedia

  • Visitor pattern — Der Besucher (engl.: visitor bzw. visitor pattern) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung und gehört zu der Kategorie der Verhaltensmuster (Behavioural Patterns). Es dient zum Kapseln von Operationen, die auf Elementen… …   Deutsch Wikipedia

  • Single-serving visitor pattern — In computer programming, the single serving visitor pattern is a design pattern. Its intent is to optimise the implementation of a visitor that is allocated, used only once, and then deleted (which is the case of most visitors). Applicability The …   Wikipedia

  • Hierarchical visitor pattern — In software engineering, the hierarchical visitor pattern is one of design patterns that intend to provide a way to visit every node in the hierarchical data structure such as a tree. See also * Visitor pattern External links *… …   Wikipedia

  • Visitor — Der Besucher (engl. visitor oder visitor pattern) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung und gehört zu der Kategorie der Verhaltensmuster (Behavioural Patterns). Es dient zum Kapseln von Operationen, die auf Elementen… …   Deutsch Wikipedia

  • Visitor (disambiguation) — A visitor is someone who visits someone else, but the term Visitor or visitors or The Visitor may also refer to:*Visitor (title), an overseer of an autonomous ecclesiastical or eleemosynary institution.In film and theatre:* The Visitors (play),… …   Wikipedia

  • Design pattern (computer science) — In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for …   Wikipedia

  • Behavioral pattern — In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.… …   Wikipedia

  • Design Pattern — Patron de conception Pour les articles homonymes, voir Patron. Un patron de conception (design pattern en anglais) est un concept de génie logiciel destiné à résoudre les problèmes récurrents suivant le paradigme objet. En français on utilise… …   Wikipédia en Français

  • Design pattern — Patron de conception Pour les articles homonymes, voir Patron. Un patron de conception (design pattern en anglais) est un concept de génie logiciel destiné à résoudre les problèmes récurrents suivant le paradigme objet. En français on utilise… …   Wikipédia en Français

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”