This article is rated Start-class on Wikipedia's
content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||||||||||||
|
I propose to remove codeproject.com from the Other links. It has 110 links on Wikipedia raising the issues of advertising, promotion, spamming, and just plain over-linking. Comments anyone?
--C# Online.NET Editor 14:51, 12 February 2007 (UTC)
I am adding problem statement to understand the design usability better.
In organization there are different kind of employees and consultants so you can make a hierarchies based upon employee profile. Like Payee->Employee-> Management, Worker, Engineer. Payee->Consultant->Management, Engineer. Each have its own salary and salary-structures and saving/saving-plans. We have some algorithms to calculate deduction from pay for each one. Now a software need to design to calculate different deductions from pay of different profile's payees. These algorithms can be in different class and those classes will be visitor class. And the software can follow the Visitor Design pattern for best design. --Akash Gupta -- 203.90.124.178 11:59, 22 Jun 2004 (UTC)
With regard to the above, the Visitor Pattern would be useful if you have an aggregate object representing the organization chart, and you want to traverse that chart, applying an algorithm to each element of the chart such that it's customized to the type of that element. The chart's accept() function provides a way to map through the chart, it's a function applicator. The visitor is the function to be applied to all parts of the chart.
If you have some conventional list of the employees, you don't need the accept() thing; you use some existing list iteration mechanism to "visit" all of these objects. Moreover, perhaps there is no need to split the algorithm away from the objects. You can perhaps just put the payment deduction into a function in the Employee class that can be overridden. Or, an Employee object can have a helper object that handles details of payroll.
for_each (employee in employee_list) { PayrollPolicy *policy = employee->getPayrollPolicy(); policy->CalculateDeduction(employee); }
The 3rd paragraph states this: "... in a conventional single-dispatch object-oriented language such as Java , Smalltalk, and C++."
I'm not directly familiar with Smalltalk, but I've always thought that Smalltalk used double-dispatch.
Can anyone confirm that?
Until we include in the article explicitly what problems this construct addresses, it will remain poor. I'm a not-very-stupid 5th degree Computer Science student and had to deduce by myself this pattern's utility: So I imagine the article will be worthless for the main reader.
Yes, please please please come up with a better example -- show the pattern saving you work and making things clearer, not multiplying the amount of code by 10x and making things harder to understand. The collection should be something that's a pain in the butt to traverse, like an incoming XML stream to be SAX-parsed. Another way to highlight the advantages of the pattern is to offer different traverses to the same visitor class(es), e.g. allow the client to apply an XPath filter to that XML traverse. -- 38.105.178.219 ( talk) 06:10, 15 October 2009 (UTC)
As far as I understand:
The pattern addresses the application of a function object (≈ closure for lispers) to each component of a composite object. Specifficaly, it is valuable when you are using multiple different functions this way in the same classes. The pattern effectively separates the code used to navigate through the composite object's structure (thus, dependant on the structure) from the code which may be applied to each component.
In the ""regular/easy way""? (I mean, without using this pattern... anybody has a better wording for that?), the navigation code would be included, redundantly, in the different function objects, maybe even intertwined with the "apllication code".
As always, the problem with code redundancy is not the repetition itself (((the code-replication problem was solved long ago by the mighty programming utils copy and paste, not to menction lisp macros ;) ))), but redundancy in code which is dependant on a decission, such as the composite objects' structure in this case. The problem arises when the decission (i.e., the structure of the object) changes: The same corrections would have to be made, again and again (because of the redundancy), across several functions in the code. This wastes programmers' time, which is very expensive, and is error-prone (as is every task requiring a human to do a search).
If redundant code isn't factored-out, the time expended in corrections would be completely lost should a new change in the decission be made.
As an additional benefit, the pattern not only eliminates the said redundancy, but also puts the navigation code in the composite class. It is desirable to have dependent code in the same module (class for O.O. languages) in which the decission they depend on is taken (in this case, the decission is the class structure, which is specified in the class declaration/definition), so it can be inmediately fetched if a change needs to be done.
Remarks, please? --
Euyyn
draw()
method for each. However, if you wanted to then draw them to an
OpenGL context, you would have to add draw_OpenGL()
methods. Then if you wanted to draw to postscript, you'd add draw_PostScript()
. Each of these additions would scatter platform-dependant drawing code across all the files of the class higherarchy. If you use the visitor pattern, you'd be adding a single class for each of these additions and that class would contain all of the platform-dependant code.draw()
method. —
BenFrantzDale 20:25, 28 November 2005 (UTC)This article is the #1 Google result for "visitor design pattern" and "visitor pattern". It needs to get better. There's lots of vague language and the organization seems poor. Also as other people have noted, the code examples are not very illuminating. Gandalfgeek ( talk) 23:12, 3 July 2008 (UTC) gandalfgeek
Some comments
Here are some things that might be of interest:
visit(Element)
for implementations not handled by special methods. The simplest Visitor implementation would thus just contain a single visit(Element)
method that performs an action applicable to any implementation. In this scenario only the navigation through the hierarchy is factored out but concrete actions remain as methods in implementation classes (MyShape.draw()
vs. MyShape.draw_OpenGL()
).MyShape.draw()
is replaced by DrawVisitor.visit(MyShape)
, MyShape.draw_OpenGL()
is replaced by OpenGLDrawVisitor.visit(MyShape)
.visitor.startVisit(this)
; call accept(visitor)
on each aggregate element; visitor.endVisit(this)
. —Preceding
unsigned comment added by
78.54.7.83 (
talk) 10:45, 19 July 2008 (UTC)Poor sample If a reader looks at the Java example, he/she might ask: what do we need the double-dispatch for here? And actually double-dispatch is only needed if there would be inheritance in the class hierarchy or at least the iteration of the subobjects is performed in the classes themself, not the visitor. So in effect, the example is very poor. —Preceding unsigned comment added by 195.243.100.246 ( talk) 14:39, 18 June 2009 (UTC)
I've created and added a UML diagram to the article. Let me know if its semi-decent. I come from a Java/C++ background, so I don't know if the diagram applies to the other languages as ubiquitously as I've assumed. I also tried uploading the original .dia file so the image my be edited easily if needed, but it complained that it wasn't a recommended image format :-/ If you want it, just drop me a line. It's not rocket-science, but it does take some time to do all that clicking. The Extremist 10:08, 9 December 2005 (UTC)
These examples have gotten out of hand. There need only be one example of this; more than one adds nothing about the pattern itself. I propose it get cut back to just one of the Java, C++, Python, or C# example, and the rest get moved to Wikibooks. Thoughts? —Ben FrantzDale 03:16, 22 May 2006 (UTC)
Where is it?
I'm not sure who wrote the previous paragraph ("Where is it?"), and at first I wasn't even sure what it meant, but now I understand: There used to be more examples and now some are gone, allegedly because only Java is needed. But if the others were moved, to where were they moved? I join in asking that question. There is a broken (i.e., red) link to visitor pattern examples. Also, there's more than Java there now: there's C++, either because it was not removed or because it has crept back in. If there are going to be multiple languages, let's please restore the Lisp, too. If there aren't, and it's because everyone can read Java, then what is C++ needed for? Although I don't especially like Java, I can live with it as the exemplar if the justification is that there should be only one language and that the first example offered was in that language. Recall that, like it or not, this is more than just documentation: the presence of extra languages here becomes a de facto advertisement for the "preferred" languages and invites every language in the universe to offer its version once a pattern has been shown (sorry for the bad pun). It would seem best not to start down that path. Netsettler ( talk) 02:23, 28 March 2008 (UTC)
Examples should show a single implementation from various classes of languages. E.g. the Java and C++ examples show really the same thing, modulo some syntax, which is not surprising as they are both statically typed OO languages. There should also be an example from a dynamic language like Python, Ruby, or Javascript, as well as a discussion of how the pattern implementation is significantly different in dynamic languages due to the use of reflection (e.g. the compiler.ast module in Python 2.5 has an idiomatic implementation of the visitor pattern). —Preceding unsigned comment added by Gandalfgeek ( talk • contribs) 04:53, 29 June 2008 (UTC)
The Lisp example is just using multiple dispatch and is not an example of a visitor pattern at all. This is confusing and I'm deleting it. The visitor pattern exists to get around the limitations of single dispatch languages, so an example in a multiple dispatch language such as Lisp is only going to confuse and mislead people. tjwoods ( talk) 20:29, 6 February 2013 (UTC)
Hmmm, I guess reading all the way through is a good thing. I just read the part of the Notes after the Lisp example that reads ...all traces of the Visitor Pattern disappear..., so I guess it is providing a useful contrast with the visitor pattern. However, I still think the presentation is confusing. Perhaps the Lisp example should be in a section such as Visitor Pattern vs. Multiple Dispatch, since these are two solutions to the same problem. tjwoods ( talk) 20:41, 6 February 2013 (UTC)
These car examples are all well and good, but fail to recognize any of the difficulties that instantly come up when traversing, say, source code or object code. I've done this several times now and the visitor pattern just doesn't seem to be reducing overhead for me - it still needs to be essentially re-written for each use, and in general causes about as many problems as it solves. I'd be interested in other people's thoughts... Dan Knapp 16:47, 24 May 2006 (UTC)
drawable
class and implement draw()
. But now suppose want to draw it to both
OpenGL and
DirectX. I'd probably put in a draw_OpenGL()
and a draw_DirectX()
method. This wouldn't scale well to more drawing modes, would spread platform-specific code across all drawable objects, and would put drawing code in classes which fundamentally represent drawable things, not ways to draw them. (That is, a cube is a cube even if it doesn't know anything about OpenGL.)A simple example that I recently implemented involved parsing wikicode. Once the wikicode had been parsed into various elements like WikiText, WikiLink etc, Visitors can be coded to output to different formats, e.g. html or plaintext.
class HTMLVisitor { public function visit(WikiLink $l) { echo "<a href=\"" . htmlentities($l->url()) . "\">" . $l->text() . "</a>"; } // ... }
class PlainTextVisitor { public function visit(WikiLink $l) { echo $l->text() . " [" . $l->url() . "]"; } // ... }
I think the visitor pattern works well for translating an intermediate format into some external format. This is why compilers use visitors to generate machine instructions for different architectures. 84.66.221.139 23:23, 11 December 2006 (UTC)
Can any one add the compiler example as it is coming in discussion so many times. For the end user it is good to know the very basic implementation of this pattern. or any link to it would be great. —Preceding unsigned comment added by 203.91.193.7 ( talk) 10:01, 30 March 2009 (UTC)
Multimethod is a more general term for "double dispatch".
Err... no. Double dispatch means you do a double-hop from a visited class back to the visitor, thereby avoiding the issue with having to perform visiting in the classes themselves. On the other hand, multimethods imply multiple dispatch where the invocation depends on the argument type in a polymorphic manner. See the C# example with dynamic dispatch for an implementation.
As I understand the visitor pattern, shouldn't the the Accept method of the Car class call Accept on the Body, Engine, and all the wheels? —The preceding unsigned comment was added by 217.166.1.202 ( talk) 10:20, 26 February 2007 (UTC).
VisitCar
which implements the traversal. —Preceding
unsigned comment added by
93.190.250.146 (
talk) 07:58, 22 July 2009 (UTC)Given that the D example adds nothing that the Java one doesn't, I'm removing it. All it does is illustrate the D language, which isn't the point of this particular article. Matthew0028 02:58, 19 June 2007 (UTC)
In my opinion the c++ code example needs to be rewritten or removed. Some issues: There's member variables in the public interface, the classes are guaranteed to leak since there's no destructors and no way to obtain pointers to the dynamically allocated memory. The Microsoft-specific "stdafx.h" precompiled header file is included. Const-correctness is not exercised. std::string objects are passed by value. A temporary iterator is stored as a member. "using namespace std;" is placed is one of the header files. I have put up a cleanup template for now. Ufretin 15:17, 3 October 2007 (UTC)
I agree, I think the C++ example is awful and must be rewritten exactly to cover some scenario where a Visitor actually makes sense. See the C# section for a corresponding example. Dnesteruk 18:49, 25 April 2016 (UTC) — Preceding unsigned comment added by 109.151.222.203 ( talk)
It seems like there should be some mention of callback, http://en.wikipedia.org/wiki/Callback_%28computer_science%29, or just a link to it somewhere within this article.
I'm not sure if expressions like "If I have a bunch of classes" are very encyclopedic. Also things like "The idea is to" is something you might see in a newsgroup post or an informal publication, not in an encyclopedia. Wopr ( talk) 14:46, 9 March 2008 (UTC)
please fixme if i am wrong. i was thinking about it and i realized that this "visitor" thing can mean "unification". color_t blue, red, green; // initialize somewhere draw_dot(red); // each color is different "object"
// versus enum color_e { BLUE, RED, GREEN, NUM_COLORS }; color_t color[NUM_COLORS]; draw_dot(color[RED]); // colors are accesed as one *color this example shows that colors are unified. but visitor is more about hoisting up same behaviour, which changes with given context. i'd like to have it clear. Xchmelmilos ( talk) 18:27, 11 March 2008 (UTC)
The narrative indicates that the Car class would call the visitor on itself, and then on each of its elements (thus the visitor need not know the structure of the Car class). The example as coded does not reflect this structure, thus providing a misleading example. I can correct this, but will first just serve notice and let the original example provider correct the code if he/she is so inclined. NedHorvath 06:42, 20 September 2008 (UTC)
Prefer NULL over 0, because:
The C++ standard doesn't guarantees that a null pointer is equal to 0. Using 0 would make you code not fully portable. Since NULL is a macro you could (re)define it ones, rater than having to edit you code in many many places.
You are completely confused. The use of 0 as a null pointer is C and C++ is completely portable, regardless of the internal representation of an actual null pointer. When used as a pointer, 0 is BY DEFINITION a null pointer. Although, I do agree that NULL--or better yet, nullptr--is better.
C++ Standard 18.1.4:
The macro NULL is an implementation-defined C++ null pointer constant in this Internnational Standard (4.10).
Footnote says:
Possible definitions include 0 and OL, but not (void*)0.
The C standard 6.3.2.3, paragraph 4 says:
Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
If the intent was that programmer used 0 instead of NULL, then it isn't logical that they consistently use the word null. Also using NULL for pointers, and only for pointers, makes your code more readable. Or as Linus [1] put it
The fact is, people who write "0" are either living in the stone age, or are not sure about the type. "0" is an _integer_.
Wikipedia also warns users NULL null pointers can be non-0.
A null pointer has a reserved value, often but not necessarily the value zero, indicating that it refers to no object.
-- Alfatrion ( talk) 00:29, 7 April 2009 (UTC)
NULL
for abstract functions but I think it's nonstandard. Will it work with
nullptr in C++0x, do you know? That is, could you do
virtual void foo() = nullptr; // or = NULL with a #define on NULL.
Whether 0 or NULL should be used where a null pointer constant is required is a style issue, and open to debate. It is however, irrelevant to the changes being made to the example source code, because a pure-specifier has nothing to do with pointers at all. The claim that 0 would not be fully portable is exactly backwards.
As stated in my initial edit summary, a pure-specifier shall always be " = 0
".
[1] On certain implementations, "= NULL
" may compile, if NULL
happens to be #defined to 0
, It may just as well be #defined to (2-2)
or 0L
,
[2]
[3] which is not a valid pure-specifier, even if some compilers may (erroneously) accept 0L
or 0x0
.
[4]
[1] Again, a pure-specifier is completely unrelated to null pointer constants, and must be " = 0
".
decltype (
talk) 08:55, 7 April 2009 (UTC)
I regret to say that this is one of the most opaque explanations I have ever read. It does not really explain it at all. Any article that you have to re-read to understand what it's trying to explain has failed. —Preceding unsigned comment added by Curmudgeon99 ( talk • contribs) 11:25, 6 April 2010 (UTC)
When you describe a design pattern you should first explain the situation you are trying to solve and then explain how the design pattern solves the problem. Use a realistic example where the design pattern is the correct one to use for the situation. Developers who learn a design pattern will often make every effort to use it in any situation because they believe it must be "good design" to use design patterns, but use them when the situation does not call for this particular pattern to be used (possibly Abstract Factory, which is often used in a similar kind of problem to Visitor). —Preceding unsigned comment added by 212.58.232.179 ( talk) 08:23, 26 July 2010 (UTC)
Two lines in the car example have accompanying comments:
interface CarElement {
void accept(CarElementVisitor visitor); // CarElements have to provide accept().
}
and
return elements.clone(); // Return a copy of the array of references.
Each comment is literally an English transliteration of the meaning of the code near it. Comments that merely recapitulate the meaning of the code they adorn are worthless, except possibly to a reader who's unfamiliar with the programming language in which the code is written. Anyone who knows Java already has all the information these comments convey, because it's plainly apparent from the source code itself.
Not wanting to passive-aggressively remove the comments myself, I'm leaving this message here instead, imploring whoever wrote the code to remove them.
71.197.144.116 ( talk) 05:14, 25 May 2010 (UTC)
interface CarElement {
void accept(CarElementVisitor visitor); // CarElements must provide an accept method.
}
just to reinforce that the interface establishes a contract for classes that implement it.-- Salix ( talk): 08:52, 25 May 2010 (UTC)
It is not correct to say that the visitor pattern "adds" functionality or "adds" virtual functions to the object or object structure. Doing so implies that dynamic modification is occurring. That is incorrect and therefore misleading...
The Visitor patterns simply walks an object structure and performs (visits) an operation on each element of that structure. That's it.
There are many ways this "visit" may occur. For example, the visit may...
The visitor pattern is a simple concepts. It is useful to have a simple example to bring that fact home...
Here, the conforming parent type, Visitable, has an Action method which accepts a delegate as the visitor operation. Action is expected to invoke the delegate, passing it's containing element. In this case, the delegate will query the type and perform an appropriate operation.
I believe this is a better explanation because it does not presume a great deal of prior knowledge (one of the purposes of explanations in general). Subsequently, a more in depth treatment may be pursued with greater success with a reader who has a stable rock solid foundation. —Preceding unsigned comment added by 174.114.248.239 ( talk) 18:18, 30 May 2010 (UTC)
Like many of the people that have left comments here, I'm having a hard time understanding this article. But it seems like these are just fancy iterators. Am I wrong? 24.130.212.167 ( talk) 08:03, 31 January 2012 (UTC)
std::pair<T,U>
. You can't just iterate over a std::pair<T,U>
because it has two different types, but you can apply a visitor that knows what to do with T
s and U
s. The usual usage, though, is for polymorphic types.
—Ben FrantzDale (
talk) 14:28, 31 January 2012 (UTC)Hi! What I miss most in the Visitor pattern article is a better description of the problem Visitor pattern intends to solve. And I'm not alone judging by the many discussions above, both recent (2012) and not-so-recent (2006). If I remember my GOF correctly, there was a section called "Motivation" to describe the real-world problem a pattern solves, and also a section called "Real world usages" or similar that gives some concrete examples (Motivation being more of an abstract description, Usages more concrete). The article about the Decorator pattern does have a Motivation paragraph already, which could be used as a style guide. Here's something to build upon:
Motivation. Large type hierarchies make adding hierarchy-wide operations (methods to every type) tedious, and if there are a lot of operations, the types become bloated and unmaintainable. For example, when representing the syntax of a program, adding a "pretty printer" operation to each syntax tree type adds noise to the source code. The visitor pattern solves this by factoring out the operation (pretty printing) to a separate class, which specializes in just pretty printing. So if you have many related types, and feel the urge to add more and more operations to (almost) every one of them, consider applying the Visitor pattern. -- Objarni ( talk) 10:57, 9 April 2012 (UTC)
@
Objarni: I'd very much like to augment the Motivation section with an accompanying image, so it'll give a visual impression of what the text is trying to archive.
But I would prefer if someone else considered whether this change would be helpful.
Here's the augmented version (just having added the image and reference numbers to the text):
Consider the design of a 2D CAD system. At its core there are several types to represent basic geometric shapes like circles, lines and arcs. The entities are ordered into layers, and at the top of the type hierarchy is the drawing, which is simply a list of layers, plus some additional properties.
A fundamental operation on this type hierarchy is saving the drawing to the system's native file format. At first glance it may seem acceptable to add local save methods to all types in the hierarchy(image item 1). But then we also want to be able to save drawings to other file formats, and adding more and more methods for saving into lots of different file formats soon clutters the relatively pure geometric data structure we started out with(image item 2).
A naive way to solve this would be to maintain separate functions for each file format(image item 3). Such a save function would take a drawing as input, traverse it and encode into that specific file format. But if you do this for several different formats, you soon begin to see lots of duplication between the functions. For example, saving a circle shape in a raster format requires very similar code no matter what specific raster form is used, and is different from other primitive shapes; the case for other primitive shapes like lines and polygons is similar. The code therefore becomes a large outer loop traversing through the objects, with a large decision tree inside the loop querying the type of the object. Another problem with this approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems.
Instead, one could apply the Visitor pattern. The Visitor pattern encodes a logical operation on the whole hierarchy into a single class containing one method per type(image item 4). In our CAD example, each save function would be implemented as a separate Visitor subclass(image item 5). This would remove all duplication of type checks and traversal steps. It would also make the compiler complain if a shape is omitted.
Another motivation is to reuse iteration code. For example iterating over a directory structure could be implemented with a visitor pattern. This would allow you to create file searches, file backups, directory removal, etc. by implementing a visitor for each function while reusing the iteration code(image item 6).
In the UML class diagram, the Visitor class implements the Visitable interface. In my opinion, this is bogus, language-wise. If something is "visitable", then it gets visited, it does not visit. It is the passive part. As such, the element being visited can be called "visitable", but not the visiting object (the visitor). 129.69.215.1 ( talk) 10:49, 2 May 2013 (UTC)
There are some (copy/paste?) typos in the UML diagram: The Element subclasses are named ConcreteElementX, but the parameter types for the Visitor methods are ConcretesElementX. — Preceding unsigned comment added by 92.78.113.9 ( talk) 10:19, 23 March 2017 (UTC)
Are you sure that Function overloading is required for the Visitor Pattern? Couldn't I just give the functions individual names, e.g. visitTypeA(TypeA a), visitTypeB(TypeB b).. instead of visit(TypeA a), visit(TypeB b). I don't think that missing function overloading hinders the implementation of this pattern. Ghinrael ( talk) 12:29, 20 July 2013 (UTC)
I thought the same. I translated the Java example to Go as straightforwardly as possible. I chose Go as it supports dispatch but not function overloading. The code works without problem and gives the same output. I just changed visit -> visitWheel, visitEngine, visitBody, visitCar as appropriate. I'll edit the article to remove the wrong statement. Bricegeumez ( talk) 15:13, 18 December 2014 (UTC)
It would actually be good to the grid of overloading in the Java example: it just makes it harder to understand. User:Soundrabbit —Preceding undated comment added 10:56, 19 August 2015 (UTC)
Is the Scala example correct? It isn't using double dispatch but instead just switching on the types, which contradicts both "The visitor takes the instance reference as input, and implements the goal through double dispatch" and "Another problem with [the naive] approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems. Instead, one could apply the Visitor pattern". I believe both those statements are correct, and that the Scala example does not properly demonstrate the visitor pattern. I know enough Scala to fix the example, if people agree, but I also would be in favour of removing it entirely as I don't think another example adds much to the article. Thoughts? ZoFreX ( talk) 16:28, 23 June 2014 (UTC)
This article exhibits blatant plagiarism of the cited external link. In the "Definition" section we have:
"The Gang of Four defines the Visitor as: "Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."—″≤
The nature of the Visitor makes it an ideal pattern to plug into public APIs thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source."
and now compare this to the text at [3]:
"The Gang of Four defines the Visitor as:
Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
The very nature of the Visitor makes it an ideal pattern to plug into public API’s, thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source..."
Outrageous! — Preceding unsigned comment added by 87.82.250.210 ( talk) 14:10, 7 January 2015 (UTC)
Someone recently seemingly did a search-and-replace operation in this article on all instances of "visitor," switching them to "Church encoding." Looking at this article to get a real understanding of what the visitor pattern is, I found this quite confusing until I looked at the edit history and realized what happened.
Perhaps whoever made this change intended to draw a parallel between Church encoding and the visitor pattern, but if so it seems to me that it would be far more beneficial simply to add a section describing the parallels. I've reverted this change in the meantime.
In the state section of the article, a pretty printing example is references, however it's not actually included in the article, or linked to anywhere. Has this been accidentally removed or does this text accidentally remain?
9point6 ( talk) 20:19, 3 February 2015 (UTC)
Not only does the State section of this article miss references or examples, I consider the gist of this section to be incorrect. Two main reasons:
Therefore I am deleting this section.
References
Isn't this:
Supposed to read:
or am I trippin? — Preceding unsigned comment added by 54.240.196.185 ( talk • contribs)
this.elements = new ICarElement[] { new Wheel("front left"),
new Wheel("front right"), new Wheel("back left") ,
new Wheel("back right"), new Body(), new Engine() };
Regarding the tip for using reflection to implement a default visitor method found in the External links as "Article Java Tip 98: Reflect on the Visitor design pattern" — am I correct in thinking this is obsolete in Java 1.8, where interfaces may have default methods? Labalius ( talk) 17:05, 8 November 2015 (UTC)
C# example STILL not a visitor pattern. The expressionprintervisitor should be a subclass of an abstract visitor. The example required that expressions know about printing. This is not what visitor is about. — Preceding unsigned comment added by 85.160.45.240 ( talk) 00:22, 10 November 2021 (UTC)
The C# classic example just uses an overridden "Print" method on each subclass and doesn't actually use the visitor pattern at all. This incorrect example is confusing to those who are trying to understand what the visitor pattern is, and should be corrected or removed. — Preceding unsigned comment added by 73.187.218.254 ( talk) 16:39, 4 September 2016 (UTC)
Yes I was about to make the same comment. The C# example is wrong and misunderstands the Visitor pattern because it requires the visitor to understand the structure of a Car. Whereas the point of the visitor pattern is that the structure knows itself and is responsible for its own traversal. If the internal organization of a car or the order in which elements must be visited is changed, the visitor should be unaffected. Houseofwealth ( talk) 05:04, 30 June 2020 (UTC)
The current Smalltalk example delegates the behavior to each object rather than separating the logic in a visitor? The following tweaked version puts the printing logic into the ExpressionPrinterVisitor
rather than in each Expression
subclass:
"There's no syntax for creating a class. Classes are created by sending messages to other classes."
WriteStream subclass: #ExpressionPrinterVisitor
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
ExpressionPrinterVisitor>>write: anExpression
"Visit given expression"
^ anExpression accept: self.
ExpressionPrinterVisitor>>visitLiteral: aLiteral
"Print a Literal object"
self nextPutAll: aLiteral value asString.
ExpressionPrinterVisitor>>visitAddition: anAddition
"Print an Addition object"
self
nextPut: $(;
nextPutAll: anAddition left asString;
nextPut: $+;
nextPutAll: anAddition right asString;
nextPut: $).
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>>value
"Getter for value"
^ value.
Literal>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitLiteral"
^aVisitor visitLiteral: self.
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>>left
"Getter for left"
^ left.
Addition>>right: anExpression
"Setter for right"
right := anExpression.
Addition>>right
"Getter for right"
^ right.
Addition>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitAddition"
^aVisitor visitAddition: self.
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 := ExpressionPrinterVisitor on: (String new: 100).
stream write: expression.
Transcript show: stream contents.
Transcript flush.
This way if any new program logic needs to be added, a new visitor class can be created which uses the visitLiteral
or visitAddition
selectors rather than having to alter the Literal
or Addition
classes.
Smalltalker2 (
talk) 17:35, 22 January 2022 (UTC)
ExpressionPrinter
and LiteralPrinter
and invoke accordingly. It's good to break down example into steps, so it's easier to consume.
AXONOV
(talk)
⚑ 13:05, 26 January 2022 (UTC)@ Alexander Davronov: Thanks, I agree that the previous version (and the above) are not presented well and should be split into more digestible parts. The previous example was definitively not the visitor pattern in that it did not separate the algorithm (printing) from the object structure (the expression types). Whether you split the visitor into smaller sub-objects as you suggest is perhaps a matter of taste, although that's not how the pattern was presented by the GoF, or in the other languages' examples in this article. Smalltalker2 ( talk) 17:35, 26 January 2022 (UTC)
In Smalltalk we can first define Expression
objects:
"There's no syntax for creating a class. Classes are created by sending messages to other classes."
Object subclass: #Expression
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
These can be sub-classed to useful types such as a literal expression type, which must respond to the #accept:
method:
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>>value
"Getter for value"
^ value.
Literal>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitLiteral"
^aVisitor visitLiteral: self.
And similarly for an addition expression type:
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>>left
"Getter for left"
^ left.
Addition>>right: anExpression
"Setter for right"
right := anExpression.
Addition>>right
"Getter for right"
^ right.
Addition>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitAddition"
^aVisitor visitAddition: self.
Then to add new logic separate from these existing classes (and without the need to modify their structure) we can define a visitor, for example for printing:
WriteStream subclass: #ExpressionPrinterVisitor
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
ExpressionPrinterVisitor>>write: anExpression
"Visit given expression"
^ anExpression accept: self.
ExpressionPrinterVisitor>>visitLiteral: aLiteral
"Print a Literal object"
self nextPutAll: aLiteral value asString.
ExpressionPrinterVisitor>>visitAddition: anAddition
"Print an Addition object"
self
nextPut: $(;
nextPutAll: anAddition left asString;
nextPut: $+;
nextPutAll: anAddition right asString;
nextPut: $).
Here the visitor needs to define methods #visitLiteral
and #visitAddition
in order to be accessed by the original expression objects. Finally we can use these objects to print an expression:
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 := ExpressionPrinterVisitor on: (String new: 100).
stream write: expression.
Transcript show: stream contents.
Transcript flush.
This could benefit from further description but I think the logic is clearer Smalltalker2 ( talk) 17:48, 26 January 2022 (UTC)
Jan 25, 2022, 16:24 - «Reverted 1 edit by 2600:1700:9E30:1590:10E2:39C9:D5DE:8DCA talk): Rv unverified, and etc.»
Jan 25, 2022, 03:22 - «Undid revision 1067490968 by Drmies talk) This is an accurate explanation of the Visitor Design Pattern and it gives a great example of a test implementation of this pattern. It is important to explain these design patterns with code examples because these patterns must themselves be implemented. If you don't find it useful Drmies, it doesn't mean others don't.»
Jan 23, 2022, 06:19 - «Undid revision 1067349395 by Drmies talk)»
Jan 23, 2022, 01:17 - «rm list of examples: we're an encyclopedia, not a collection of examples of unverified code»
AXONOV (talk) ⚑ 17:48, 25 January 2022 (UTC)
This article is rated Start-class on Wikipedia's
content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||||||||||||
|
I propose to remove codeproject.com from the Other links. It has 110 links on Wikipedia raising the issues of advertising, promotion, spamming, and just plain over-linking. Comments anyone?
--C# Online.NET Editor 14:51, 12 February 2007 (UTC)
I am adding problem statement to understand the design usability better.
In organization there are different kind of employees and consultants so you can make a hierarchies based upon employee profile. Like Payee->Employee-> Management, Worker, Engineer. Payee->Consultant->Management, Engineer. Each have its own salary and salary-structures and saving/saving-plans. We have some algorithms to calculate deduction from pay for each one. Now a software need to design to calculate different deductions from pay of different profile's payees. These algorithms can be in different class and those classes will be visitor class. And the software can follow the Visitor Design pattern for best design. --Akash Gupta -- 203.90.124.178 11:59, 22 Jun 2004 (UTC)
With regard to the above, the Visitor Pattern would be useful if you have an aggregate object representing the organization chart, and you want to traverse that chart, applying an algorithm to each element of the chart such that it's customized to the type of that element. The chart's accept() function provides a way to map through the chart, it's a function applicator. The visitor is the function to be applied to all parts of the chart.
If you have some conventional list of the employees, you don't need the accept() thing; you use some existing list iteration mechanism to "visit" all of these objects. Moreover, perhaps there is no need to split the algorithm away from the objects. You can perhaps just put the payment deduction into a function in the Employee class that can be overridden. Or, an Employee object can have a helper object that handles details of payroll.
for_each (employee in employee_list) { PayrollPolicy *policy = employee->getPayrollPolicy(); policy->CalculateDeduction(employee); }
The 3rd paragraph states this: "... in a conventional single-dispatch object-oriented language such as Java , Smalltalk, and C++."
I'm not directly familiar with Smalltalk, but I've always thought that Smalltalk used double-dispatch.
Can anyone confirm that?
Until we include in the article explicitly what problems this construct addresses, it will remain poor. I'm a not-very-stupid 5th degree Computer Science student and had to deduce by myself this pattern's utility: So I imagine the article will be worthless for the main reader.
Yes, please please please come up with a better example -- show the pattern saving you work and making things clearer, not multiplying the amount of code by 10x and making things harder to understand. The collection should be something that's a pain in the butt to traverse, like an incoming XML stream to be SAX-parsed. Another way to highlight the advantages of the pattern is to offer different traverses to the same visitor class(es), e.g. allow the client to apply an XPath filter to that XML traverse. -- 38.105.178.219 ( talk) 06:10, 15 October 2009 (UTC)
As far as I understand:
The pattern addresses the application of a function object (≈ closure for lispers) to each component of a composite object. Specifficaly, it is valuable when you are using multiple different functions this way in the same classes. The pattern effectively separates the code used to navigate through the composite object's structure (thus, dependant on the structure) from the code which may be applied to each component.
In the ""regular/easy way""? (I mean, without using this pattern... anybody has a better wording for that?), the navigation code would be included, redundantly, in the different function objects, maybe even intertwined with the "apllication code".
As always, the problem with code redundancy is not the repetition itself (((the code-replication problem was solved long ago by the mighty programming utils copy and paste, not to menction lisp macros ;) ))), but redundancy in code which is dependant on a decission, such as the composite objects' structure in this case. The problem arises when the decission (i.e., the structure of the object) changes: The same corrections would have to be made, again and again (because of the redundancy), across several functions in the code. This wastes programmers' time, which is very expensive, and is error-prone (as is every task requiring a human to do a search).
If redundant code isn't factored-out, the time expended in corrections would be completely lost should a new change in the decission be made.
As an additional benefit, the pattern not only eliminates the said redundancy, but also puts the navigation code in the composite class. It is desirable to have dependent code in the same module (class for O.O. languages) in which the decission they depend on is taken (in this case, the decission is the class structure, which is specified in the class declaration/definition), so it can be inmediately fetched if a change needs to be done.
Remarks, please? --
Euyyn
draw()
method for each. However, if you wanted to then draw them to an
OpenGL context, you would have to add draw_OpenGL()
methods. Then if you wanted to draw to postscript, you'd add draw_PostScript()
. Each of these additions would scatter platform-dependant drawing code across all the files of the class higherarchy. If you use the visitor pattern, you'd be adding a single class for each of these additions and that class would contain all of the platform-dependant code.draw()
method. —
BenFrantzDale 20:25, 28 November 2005 (UTC)This article is the #1 Google result for "visitor design pattern" and "visitor pattern". It needs to get better. There's lots of vague language and the organization seems poor. Also as other people have noted, the code examples are not very illuminating. Gandalfgeek ( talk) 23:12, 3 July 2008 (UTC) gandalfgeek
Some comments
Here are some things that might be of interest:
visit(Element)
for implementations not handled by special methods. The simplest Visitor implementation would thus just contain a single visit(Element)
method that performs an action applicable to any implementation. In this scenario only the navigation through the hierarchy is factored out but concrete actions remain as methods in implementation classes (MyShape.draw()
vs. MyShape.draw_OpenGL()
).MyShape.draw()
is replaced by DrawVisitor.visit(MyShape)
, MyShape.draw_OpenGL()
is replaced by OpenGLDrawVisitor.visit(MyShape)
.visitor.startVisit(this)
; call accept(visitor)
on each aggregate element; visitor.endVisit(this)
. —Preceding
unsigned comment added by
78.54.7.83 (
talk) 10:45, 19 July 2008 (UTC)Poor sample If a reader looks at the Java example, he/she might ask: what do we need the double-dispatch for here? And actually double-dispatch is only needed if there would be inheritance in the class hierarchy or at least the iteration of the subobjects is performed in the classes themself, not the visitor. So in effect, the example is very poor. —Preceding unsigned comment added by 195.243.100.246 ( talk) 14:39, 18 June 2009 (UTC)
I've created and added a UML diagram to the article. Let me know if its semi-decent. I come from a Java/C++ background, so I don't know if the diagram applies to the other languages as ubiquitously as I've assumed. I also tried uploading the original .dia file so the image my be edited easily if needed, but it complained that it wasn't a recommended image format :-/ If you want it, just drop me a line. It's not rocket-science, but it does take some time to do all that clicking. The Extremist 10:08, 9 December 2005 (UTC)
These examples have gotten out of hand. There need only be one example of this; more than one adds nothing about the pattern itself. I propose it get cut back to just one of the Java, C++, Python, or C# example, and the rest get moved to Wikibooks. Thoughts? —Ben FrantzDale 03:16, 22 May 2006 (UTC)
Where is it?
I'm not sure who wrote the previous paragraph ("Where is it?"), and at first I wasn't even sure what it meant, but now I understand: There used to be more examples and now some are gone, allegedly because only Java is needed. But if the others were moved, to where were they moved? I join in asking that question. There is a broken (i.e., red) link to visitor pattern examples. Also, there's more than Java there now: there's C++, either because it was not removed or because it has crept back in. If there are going to be multiple languages, let's please restore the Lisp, too. If there aren't, and it's because everyone can read Java, then what is C++ needed for? Although I don't especially like Java, I can live with it as the exemplar if the justification is that there should be only one language and that the first example offered was in that language. Recall that, like it or not, this is more than just documentation: the presence of extra languages here becomes a de facto advertisement for the "preferred" languages and invites every language in the universe to offer its version once a pattern has been shown (sorry for the bad pun). It would seem best not to start down that path. Netsettler ( talk) 02:23, 28 March 2008 (UTC)
Examples should show a single implementation from various classes of languages. E.g. the Java and C++ examples show really the same thing, modulo some syntax, which is not surprising as they are both statically typed OO languages. There should also be an example from a dynamic language like Python, Ruby, or Javascript, as well as a discussion of how the pattern implementation is significantly different in dynamic languages due to the use of reflection (e.g. the compiler.ast module in Python 2.5 has an idiomatic implementation of the visitor pattern). —Preceding unsigned comment added by Gandalfgeek ( talk • contribs) 04:53, 29 June 2008 (UTC)
The Lisp example is just using multiple dispatch and is not an example of a visitor pattern at all. This is confusing and I'm deleting it. The visitor pattern exists to get around the limitations of single dispatch languages, so an example in a multiple dispatch language such as Lisp is only going to confuse and mislead people. tjwoods ( talk) 20:29, 6 February 2013 (UTC)
Hmmm, I guess reading all the way through is a good thing. I just read the part of the Notes after the Lisp example that reads ...all traces of the Visitor Pattern disappear..., so I guess it is providing a useful contrast with the visitor pattern. However, I still think the presentation is confusing. Perhaps the Lisp example should be in a section such as Visitor Pattern vs. Multiple Dispatch, since these are two solutions to the same problem. tjwoods ( talk) 20:41, 6 February 2013 (UTC)
These car examples are all well and good, but fail to recognize any of the difficulties that instantly come up when traversing, say, source code or object code. I've done this several times now and the visitor pattern just doesn't seem to be reducing overhead for me - it still needs to be essentially re-written for each use, and in general causes about as many problems as it solves. I'd be interested in other people's thoughts... Dan Knapp 16:47, 24 May 2006 (UTC)
drawable
class and implement draw()
. But now suppose want to draw it to both
OpenGL and
DirectX. I'd probably put in a draw_OpenGL()
and a draw_DirectX()
method. This wouldn't scale well to more drawing modes, would spread platform-specific code across all drawable objects, and would put drawing code in classes which fundamentally represent drawable things, not ways to draw them. (That is, a cube is a cube even if it doesn't know anything about OpenGL.)A simple example that I recently implemented involved parsing wikicode. Once the wikicode had been parsed into various elements like WikiText, WikiLink etc, Visitors can be coded to output to different formats, e.g. html or plaintext.
class HTMLVisitor { public function visit(WikiLink $l) { echo "<a href=\"" . htmlentities($l->url()) . "\">" . $l->text() . "</a>"; } // ... }
class PlainTextVisitor { public function visit(WikiLink $l) { echo $l->text() . " [" . $l->url() . "]"; } // ... }
I think the visitor pattern works well for translating an intermediate format into some external format. This is why compilers use visitors to generate machine instructions for different architectures. 84.66.221.139 23:23, 11 December 2006 (UTC)
Can any one add the compiler example as it is coming in discussion so many times. For the end user it is good to know the very basic implementation of this pattern. or any link to it would be great. —Preceding unsigned comment added by 203.91.193.7 ( talk) 10:01, 30 March 2009 (UTC)
Multimethod is a more general term for "double dispatch".
Err... no. Double dispatch means you do a double-hop from a visited class back to the visitor, thereby avoiding the issue with having to perform visiting in the classes themselves. On the other hand, multimethods imply multiple dispatch where the invocation depends on the argument type in a polymorphic manner. See the C# example with dynamic dispatch for an implementation.
As I understand the visitor pattern, shouldn't the the Accept method of the Car class call Accept on the Body, Engine, and all the wheels? —The preceding unsigned comment was added by 217.166.1.202 ( talk) 10:20, 26 February 2007 (UTC).
VisitCar
which implements the traversal. —Preceding
unsigned comment added by
93.190.250.146 (
talk) 07:58, 22 July 2009 (UTC)Given that the D example adds nothing that the Java one doesn't, I'm removing it. All it does is illustrate the D language, which isn't the point of this particular article. Matthew0028 02:58, 19 June 2007 (UTC)
In my opinion the c++ code example needs to be rewritten or removed. Some issues: There's member variables in the public interface, the classes are guaranteed to leak since there's no destructors and no way to obtain pointers to the dynamically allocated memory. The Microsoft-specific "stdafx.h" precompiled header file is included. Const-correctness is not exercised. std::string objects are passed by value. A temporary iterator is stored as a member. "using namespace std;" is placed is one of the header files. I have put up a cleanup template for now. Ufretin 15:17, 3 October 2007 (UTC)
I agree, I think the C++ example is awful and must be rewritten exactly to cover some scenario where a Visitor actually makes sense. See the C# section for a corresponding example. Dnesteruk 18:49, 25 April 2016 (UTC) — Preceding unsigned comment added by 109.151.222.203 ( talk)
It seems like there should be some mention of callback, http://en.wikipedia.org/wiki/Callback_%28computer_science%29, or just a link to it somewhere within this article.
I'm not sure if expressions like "If I have a bunch of classes" are very encyclopedic. Also things like "The idea is to" is something you might see in a newsgroup post or an informal publication, not in an encyclopedia. Wopr ( talk) 14:46, 9 March 2008 (UTC)
please fixme if i am wrong. i was thinking about it and i realized that this "visitor" thing can mean "unification". color_t blue, red, green; // initialize somewhere draw_dot(red); // each color is different "object"
// versus enum color_e { BLUE, RED, GREEN, NUM_COLORS }; color_t color[NUM_COLORS]; draw_dot(color[RED]); // colors are accesed as one *color this example shows that colors are unified. but visitor is more about hoisting up same behaviour, which changes with given context. i'd like to have it clear. Xchmelmilos ( talk) 18:27, 11 March 2008 (UTC)
The narrative indicates that the Car class would call the visitor on itself, and then on each of its elements (thus the visitor need not know the structure of the Car class). The example as coded does not reflect this structure, thus providing a misleading example. I can correct this, but will first just serve notice and let the original example provider correct the code if he/she is so inclined. NedHorvath 06:42, 20 September 2008 (UTC)
Prefer NULL over 0, because:
The C++ standard doesn't guarantees that a null pointer is equal to 0. Using 0 would make you code not fully portable. Since NULL is a macro you could (re)define it ones, rater than having to edit you code in many many places.
You are completely confused. The use of 0 as a null pointer is C and C++ is completely portable, regardless of the internal representation of an actual null pointer. When used as a pointer, 0 is BY DEFINITION a null pointer. Although, I do agree that NULL--or better yet, nullptr--is better.
C++ Standard 18.1.4:
The macro NULL is an implementation-defined C++ null pointer constant in this Internnational Standard (4.10).
Footnote says:
Possible definitions include 0 and OL, but not (void*)0.
The C standard 6.3.2.3, paragraph 4 says:
Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
If the intent was that programmer used 0 instead of NULL, then it isn't logical that they consistently use the word null. Also using NULL for pointers, and only for pointers, makes your code more readable. Or as Linus [1] put it
The fact is, people who write "0" are either living in the stone age, or are not sure about the type. "0" is an _integer_.
Wikipedia also warns users NULL null pointers can be non-0.
A null pointer has a reserved value, often but not necessarily the value zero, indicating that it refers to no object.
-- Alfatrion ( talk) 00:29, 7 April 2009 (UTC)
NULL
for abstract functions but I think it's nonstandard. Will it work with
nullptr in C++0x, do you know? That is, could you do
virtual void foo() = nullptr; // or = NULL with a #define on NULL.
Whether 0 or NULL should be used where a null pointer constant is required is a style issue, and open to debate. It is however, irrelevant to the changes being made to the example source code, because a pure-specifier has nothing to do with pointers at all. The claim that 0 would not be fully portable is exactly backwards.
As stated in my initial edit summary, a pure-specifier shall always be " = 0
".
[1] On certain implementations, "= NULL
" may compile, if NULL
happens to be #defined to 0
, It may just as well be #defined to (2-2)
or 0L
,
[2]
[3] which is not a valid pure-specifier, even if some compilers may (erroneously) accept 0L
or 0x0
.
[4]
[1] Again, a pure-specifier is completely unrelated to null pointer constants, and must be " = 0
".
decltype (
talk) 08:55, 7 April 2009 (UTC)
I regret to say that this is one of the most opaque explanations I have ever read. It does not really explain it at all. Any article that you have to re-read to understand what it's trying to explain has failed. —Preceding unsigned comment added by Curmudgeon99 ( talk • contribs) 11:25, 6 April 2010 (UTC)
When you describe a design pattern you should first explain the situation you are trying to solve and then explain how the design pattern solves the problem. Use a realistic example where the design pattern is the correct one to use for the situation. Developers who learn a design pattern will often make every effort to use it in any situation because they believe it must be "good design" to use design patterns, but use them when the situation does not call for this particular pattern to be used (possibly Abstract Factory, which is often used in a similar kind of problem to Visitor). —Preceding unsigned comment added by 212.58.232.179 ( talk) 08:23, 26 July 2010 (UTC)
Two lines in the car example have accompanying comments:
interface CarElement {
void accept(CarElementVisitor visitor); // CarElements have to provide accept().
}
and
return elements.clone(); // Return a copy of the array of references.
Each comment is literally an English transliteration of the meaning of the code near it. Comments that merely recapitulate the meaning of the code they adorn are worthless, except possibly to a reader who's unfamiliar with the programming language in which the code is written. Anyone who knows Java already has all the information these comments convey, because it's plainly apparent from the source code itself.
Not wanting to passive-aggressively remove the comments myself, I'm leaving this message here instead, imploring whoever wrote the code to remove them.
71.197.144.116 ( talk) 05:14, 25 May 2010 (UTC)
interface CarElement {
void accept(CarElementVisitor visitor); // CarElements must provide an accept method.
}
just to reinforce that the interface establishes a contract for classes that implement it.-- Salix ( talk): 08:52, 25 May 2010 (UTC)
It is not correct to say that the visitor pattern "adds" functionality or "adds" virtual functions to the object or object structure. Doing so implies that dynamic modification is occurring. That is incorrect and therefore misleading...
The Visitor patterns simply walks an object structure and performs (visits) an operation on each element of that structure. That's it.
There are many ways this "visit" may occur. For example, the visit may...
The visitor pattern is a simple concepts. It is useful to have a simple example to bring that fact home...
Here, the conforming parent type, Visitable, has an Action method which accepts a delegate as the visitor operation. Action is expected to invoke the delegate, passing it's containing element. In this case, the delegate will query the type and perform an appropriate operation.
I believe this is a better explanation because it does not presume a great deal of prior knowledge (one of the purposes of explanations in general). Subsequently, a more in depth treatment may be pursued with greater success with a reader who has a stable rock solid foundation. —Preceding unsigned comment added by 174.114.248.239 ( talk) 18:18, 30 May 2010 (UTC)
Like many of the people that have left comments here, I'm having a hard time understanding this article. But it seems like these are just fancy iterators. Am I wrong? 24.130.212.167 ( talk) 08:03, 31 January 2012 (UTC)
std::pair<T,U>
. You can't just iterate over a std::pair<T,U>
because it has two different types, but you can apply a visitor that knows what to do with T
s and U
s. The usual usage, though, is for polymorphic types.
—Ben FrantzDale (
talk) 14:28, 31 January 2012 (UTC)Hi! What I miss most in the Visitor pattern article is a better description of the problem Visitor pattern intends to solve. And I'm not alone judging by the many discussions above, both recent (2012) and not-so-recent (2006). If I remember my GOF correctly, there was a section called "Motivation" to describe the real-world problem a pattern solves, and also a section called "Real world usages" or similar that gives some concrete examples (Motivation being more of an abstract description, Usages more concrete). The article about the Decorator pattern does have a Motivation paragraph already, which could be used as a style guide. Here's something to build upon:
Motivation. Large type hierarchies make adding hierarchy-wide operations (methods to every type) tedious, and if there are a lot of operations, the types become bloated and unmaintainable. For example, when representing the syntax of a program, adding a "pretty printer" operation to each syntax tree type adds noise to the source code. The visitor pattern solves this by factoring out the operation (pretty printing) to a separate class, which specializes in just pretty printing. So if you have many related types, and feel the urge to add more and more operations to (almost) every one of them, consider applying the Visitor pattern. -- Objarni ( talk) 10:57, 9 April 2012 (UTC)
@
Objarni: I'd very much like to augment the Motivation section with an accompanying image, so it'll give a visual impression of what the text is trying to archive.
But I would prefer if someone else considered whether this change would be helpful.
Here's the augmented version (just having added the image and reference numbers to the text):
Consider the design of a 2D CAD system. At its core there are several types to represent basic geometric shapes like circles, lines and arcs. The entities are ordered into layers, and at the top of the type hierarchy is the drawing, which is simply a list of layers, plus some additional properties.
A fundamental operation on this type hierarchy is saving the drawing to the system's native file format. At first glance it may seem acceptable to add local save methods to all types in the hierarchy(image item 1). But then we also want to be able to save drawings to other file formats, and adding more and more methods for saving into lots of different file formats soon clutters the relatively pure geometric data structure we started out with(image item 2).
A naive way to solve this would be to maintain separate functions for each file format(image item 3). Such a save function would take a drawing as input, traverse it and encode into that specific file format. But if you do this for several different formats, you soon begin to see lots of duplication between the functions. For example, saving a circle shape in a raster format requires very similar code no matter what specific raster form is used, and is different from other primitive shapes; the case for other primitive shapes like lines and polygons is similar. The code therefore becomes a large outer loop traversing through the objects, with a large decision tree inside the loop querying the type of the object. Another problem with this approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems.
Instead, one could apply the Visitor pattern. The Visitor pattern encodes a logical operation on the whole hierarchy into a single class containing one method per type(image item 4). In our CAD example, each save function would be implemented as a separate Visitor subclass(image item 5). This would remove all duplication of type checks and traversal steps. It would also make the compiler complain if a shape is omitted.
Another motivation is to reuse iteration code. For example iterating over a directory structure could be implemented with a visitor pattern. This would allow you to create file searches, file backups, directory removal, etc. by implementing a visitor for each function while reusing the iteration code(image item 6).
In the UML class diagram, the Visitor class implements the Visitable interface. In my opinion, this is bogus, language-wise. If something is "visitable", then it gets visited, it does not visit. It is the passive part. As such, the element being visited can be called "visitable", but not the visiting object (the visitor). 129.69.215.1 ( talk) 10:49, 2 May 2013 (UTC)
There are some (copy/paste?) typos in the UML diagram: The Element subclasses are named ConcreteElementX, but the parameter types for the Visitor methods are ConcretesElementX. — Preceding unsigned comment added by 92.78.113.9 ( talk) 10:19, 23 March 2017 (UTC)
Are you sure that Function overloading is required for the Visitor Pattern? Couldn't I just give the functions individual names, e.g. visitTypeA(TypeA a), visitTypeB(TypeB b).. instead of visit(TypeA a), visit(TypeB b). I don't think that missing function overloading hinders the implementation of this pattern. Ghinrael ( talk) 12:29, 20 July 2013 (UTC)
I thought the same. I translated the Java example to Go as straightforwardly as possible. I chose Go as it supports dispatch but not function overloading. The code works without problem and gives the same output. I just changed visit -> visitWheel, visitEngine, visitBody, visitCar as appropriate. I'll edit the article to remove the wrong statement. Bricegeumez ( talk) 15:13, 18 December 2014 (UTC)
It would actually be good to the grid of overloading in the Java example: it just makes it harder to understand. User:Soundrabbit —Preceding undated comment added 10:56, 19 August 2015 (UTC)
Is the Scala example correct? It isn't using double dispatch but instead just switching on the types, which contradicts both "The visitor takes the instance reference as input, and implements the goal through double dispatch" and "Another problem with [the naive] approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems. Instead, one could apply the Visitor pattern". I believe both those statements are correct, and that the Scala example does not properly demonstrate the visitor pattern. I know enough Scala to fix the example, if people agree, but I also would be in favour of removing it entirely as I don't think another example adds much to the article. Thoughts? ZoFreX ( talk) 16:28, 23 June 2014 (UTC)
This article exhibits blatant plagiarism of the cited external link. In the "Definition" section we have:
"The Gang of Four defines the Visitor as: "Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."—″≤
The nature of the Visitor makes it an ideal pattern to plug into public APIs thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source."
and now compare this to the text at [3]:
"The Gang of Four defines the Visitor as:
Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
The very nature of the Visitor makes it an ideal pattern to plug into public API’s, thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source..."
Outrageous! — Preceding unsigned comment added by 87.82.250.210 ( talk) 14:10, 7 January 2015 (UTC)
Someone recently seemingly did a search-and-replace operation in this article on all instances of "visitor," switching them to "Church encoding." Looking at this article to get a real understanding of what the visitor pattern is, I found this quite confusing until I looked at the edit history and realized what happened.
Perhaps whoever made this change intended to draw a parallel between Church encoding and the visitor pattern, but if so it seems to me that it would be far more beneficial simply to add a section describing the parallels. I've reverted this change in the meantime.
In the state section of the article, a pretty printing example is references, however it's not actually included in the article, or linked to anywhere. Has this been accidentally removed or does this text accidentally remain?
9point6 ( talk) 20:19, 3 February 2015 (UTC)
Not only does the State section of this article miss references or examples, I consider the gist of this section to be incorrect. Two main reasons:
Therefore I am deleting this section.
References
Isn't this:
Supposed to read:
or am I trippin? — Preceding unsigned comment added by 54.240.196.185 ( talk • contribs)
this.elements = new ICarElement[] { new Wheel("front left"),
new Wheel("front right"), new Wheel("back left") ,
new Wheel("back right"), new Body(), new Engine() };
Regarding the tip for using reflection to implement a default visitor method found in the External links as "Article Java Tip 98: Reflect on the Visitor design pattern" — am I correct in thinking this is obsolete in Java 1.8, where interfaces may have default methods? Labalius ( talk) 17:05, 8 November 2015 (UTC)
C# example STILL not a visitor pattern. The expressionprintervisitor should be a subclass of an abstract visitor. The example required that expressions know about printing. This is not what visitor is about. — Preceding unsigned comment added by 85.160.45.240 ( talk) 00:22, 10 November 2021 (UTC)
The C# classic example just uses an overridden "Print" method on each subclass and doesn't actually use the visitor pattern at all. This incorrect example is confusing to those who are trying to understand what the visitor pattern is, and should be corrected or removed. — Preceding unsigned comment added by 73.187.218.254 ( talk) 16:39, 4 September 2016 (UTC)
Yes I was about to make the same comment. The C# example is wrong and misunderstands the Visitor pattern because it requires the visitor to understand the structure of a Car. Whereas the point of the visitor pattern is that the structure knows itself and is responsible for its own traversal. If the internal organization of a car or the order in which elements must be visited is changed, the visitor should be unaffected. Houseofwealth ( talk) 05:04, 30 June 2020 (UTC)
The current Smalltalk example delegates the behavior to each object rather than separating the logic in a visitor? The following tweaked version puts the printing logic into the ExpressionPrinterVisitor
rather than in each Expression
subclass:
"There's no syntax for creating a class. Classes are created by sending messages to other classes."
WriteStream subclass: #ExpressionPrinterVisitor
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
ExpressionPrinterVisitor>>write: anExpression
"Visit given expression"
^ anExpression accept: self.
ExpressionPrinterVisitor>>visitLiteral: aLiteral
"Print a Literal object"
self nextPutAll: aLiteral value asString.
ExpressionPrinterVisitor>>visitAddition: anAddition
"Print an Addition object"
self
nextPut: $(;
nextPutAll: anAddition left asString;
nextPut: $+;
nextPutAll: anAddition right asString;
nextPut: $).
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>>value
"Getter for value"
^ value.
Literal>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitLiteral"
^aVisitor visitLiteral: self.
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>>left
"Getter for left"
^ left.
Addition>>right: anExpression
"Setter for right"
right := anExpression.
Addition>>right
"Getter for right"
^ right.
Addition>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitAddition"
^aVisitor visitAddition: self.
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 := ExpressionPrinterVisitor on: (String new: 100).
stream write: expression.
Transcript show: stream contents.
Transcript flush.
This way if any new program logic needs to be added, a new visitor class can be created which uses the visitLiteral
or visitAddition
selectors rather than having to alter the Literal
or Addition
classes.
Smalltalker2 (
talk) 17:35, 22 January 2022 (UTC)
ExpressionPrinter
and LiteralPrinter
and invoke accordingly. It's good to break down example into steps, so it's easier to consume.
AXONOV
(talk)
⚑ 13:05, 26 January 2022 (UTC)@ Alexander Davronov: Thanks, I agree that the previous version (and the above) are not presented well and should be split into more digestible parts. The previous example was definitively not the visitor pattern in that it did not separate the algorithm (printing) from the object structure (the expression types). Whether you split the visitor into smaller sub-objects as you suggest is perhaps a matter of taste, although that's not how the pattern was presented by the GoF, or in the other languages' examples in this article. Smalltalker2 ( talk) 17:35, 26 January 2022 (UTC)
In Smalltalk we can first define Expression
objects:
"There's no syntax for creating a class. Classes are created by sending messages to other classes."
Object subclass: #Expression
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
These can be sub-classed to useful types such as a literal expression type, which must respond to the #accept:
method:
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>>value
"Getter for value"
^ value.
Literal>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitLiteral"
^aVisitor visitLiteral: self.
And similarly for an addition expression type:
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>>left
"Getter for left"
^ left.
Addition>>right: anExpression
"Setter for right"
right := anExpression.
Addition>>right
"Getter for right"
^ right.
Addition>>accept: aVisitor
"Delegate behaviour to visitor which must implement visitAddition"
^aVisitor visitAddition: self.
Then to add new logic separate from these existing classes (and without the need to modify their structure) we can define a visitor, for example for printing:
WriteStream subclass: #ExpressionPrinterVisitor
instanceVariableNames: ''
classVariableNames: ''
package: 'Wikipedia'.
ExpressionPrinterVisitor>>write: anExpression
"Visit given expression"
^ anExpression accept: self.
ExpressionPrinterVisitor>>visitLiteral: aLiteral
"Print a Literal object"
self nextPutAll: aLiteral value asString.
ExpressionPrinterVisitor>>visitAddition: anAddition
"Print an Addition object"
self
nextPut: $(;
nextPutAll: anAddition left asString;
nextPut: $+;
nextPutAll: anAddition right asString;
nextPut: $).
Here the visitor needs to define methods #visitLiteral
and #visitAddition
in order to be accessed by the original expression objects. Finally we can use these objects to print an expression:
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 := ExpressionPrinterVisitor on: (String new: 100).
stream write: expression.
Transcript show: stream contents.
Transcript flush.
This could benefit from further description but I think the logic is clearer Smalltalker2 ( talk) 17:48, 26 January 2022 (UTC)
Jan 25, 2022, 16:24 - «Reverted 1 edit by 2600:1700:9E30:1590:10E2:39C9:D5DE:8DCA talk): Rv unverified, and etc.»
Jan 25, 2022, 03:22 - «Undid revision 1067490968 by Drmies talk) This is an accurate explanation of the Visitor Design Pattern and it gives a great example of a test implementation of this pattern. It is important to explain these design patterns with code examples because these patterns must themselves be implemented. If you don't find it useful Drmies, it doesn't mean others don't.»
Jan 23, 2022, 06:19 - «Undid revision 1067349395 by Drmies talk)»
Jan 23, 2022, 01:17 - «rm list of examples: we're an encyclopedia, not a collection of examples of unverified code»
AXONOV (talk) ⚑ 17:48, 25 January 2022 (UTC)