Jump to content

Talk:Visitor pattern

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by MatthieuWiki (talk | contribs) at 17:26, 13 July 2007 (UML). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

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);
}


Smalltalk single dispatch?

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?


Well, I think I'd also heard that, but a simple look at SmallTalk shows it's not allowed by the sintax: You write an object (or an expression returning an object) and then a message to send to it ("method to invocate on it")... And define methods writing "Class>>Message: Argument[s]"... So unless something is ommited in the article, there's no way to define double-dispatch methods.
(Well, it's the first time I look at SmallTalk, so perhaps I'm wrong =) )
-- User:E-uyyn

Some poorness

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.

I agree with this assessment. Once the usefulness finally occurred to me (no reflection needed to handle different types), I went to the Java and C# example and expected to see the VisitorDemo iterating over a bunch of objects of indeterminate type and not having to use reflection. Instead, VisitorDemo just creates a Car object. The Visitor pattern isn't even useful in this scenario. Can we please get some better examples, and some better code samples? ThePedanticPrick 15:53, 12 April 2006 (UTC)[reply]
Ok, wait, I get it now. Car.accept passes the visitor to the accept methods of its components. I should have read more carefully. Nevertheless, this highlights the need for more clarity on the page. Also, it seems like there's more than one benefit to using this. There's the simulation of double dispatch, or what I called "no reflection needed", there's the ability to let an object handle its own component composition (also something we need to explain more clearly), and what BenFrantzDale describes below, the ability to decouple the function from the objects. He also goes on to describe something I don't fully understand yet, not being a graphics guy. ThePedanticPrick 19:27, 12 April 2006 (UTC)[reply]


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

The use described in Design Patterns is to move a higherarchy of methods into one place so that adding more such methods doesn't get out of hand. For example, if you have objects that will be drawn on the screen, you could have a 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.
Furthermore, if you have objects in scenegraph, you might want to draw them in different orders depending on the nature of the drawing context. For example, in OpenGL you might want to draw all brick-textured objects together to avoid excess context switching. The OpenGL visitor could collect a list of things to draw, sorted by texture usage, and only then would you draw the scene. This could not be accomplished easily with a simple recursive draw() method. —BenFrantzDale 20:25, 28 November 2005 (UTC)[reply]

UML

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)[reply]

Examples

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)[reply]

Where is it?

How about a more realistic example...?

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)[reply]

You might want to take a look at "Visitor Combination and Traversal Control" by Joost Visser - it specifically addresses visitor reuse and traversal strategies. 129.34.20.19 14:22, 29 June 2006 (UTC)[reply]
The key is that it gives you double dispatch. This essentially allows you to add virtual methods to classes that already exist. As a result, you get the power of virtual methods without having to add bloat to the classes. Plus it localizes a particular algorithm to one class rather than scattering it across classes.
For example, suppose I have a scenegraph with heterogenious objects that I want to draw. One way to draw this would be to have each object inherit some 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.)
In contrast, using the visitor pattern the OpenGL drawing functions would all be in one file, the DirectX functions in another file, and adding another drawing mode would simply be a matter of adding a third file.
Does that help? —Ben FrantzDale 22:25, 27 July 2006 (UTC)[reply]
Yes, that tells me a lot more about what one is supposed to gain from the pattern. I'm used to languages that have multimethods anyway, which was part of why I didn't get it.
I do feel compelled to point out that realistically, it's unlikely one would want a third 3D API, but the separation you describe is definitely a good thing.
Thanks. Dan Knapp 03:50, 8 November 2006 (UTC)[reply]

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)[reply]

Multimethod

Multimethod is a more general term for "double dispatch"

Car class in example is wrong?

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).[reply]

I agree with the above comment. The responsibility of a visitable object is to provide navigation to sub-components. A visitor would only be interested in adding extended functionality to individual nodes and should not be aware of how the nodes are linked. This is the responsibility of the aggregated object itself. --Pav007 11:53, 14 March 2007 (UTC)[reply]
I don't have Patterns in front of me, but I believe it can go either way. —Ben FrantzDale 12:05, 14 March 2007 (UTC)[reply]
It does seem to contradict the article though, which says: "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". Now, this implies that things can be different (needs clarification, by the way), but one would hope that the example should demonstrate the "simplest version" anyway. So i'm going ahead and fixing it. -- int19h 17:24, 15 March 2007 (UTC)[reply]

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);
}


Smalltalk single dispatch?

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?


Well, I think I'd also heard that, but a simple look at SmallTalk shows it's not allowed by the sintax: You write an object (or an expression returning an object) and then a message to send to it ("method to invocate on it")... And define methods writing "Class>>Message: Argument[s]"... So unless something is ommited in the article, there's no way to define double-dispatch methods.
(Well, it's the first time I look at SmallTalk, so perhaps I'm wrong =) )
-- User:E-uyyn

Some poorness

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.

I agree with this assessment. Once the usefulness finally occurred to me (no reflection needed to handle different types), I went to the Java and C# example and expected to see the VisitorDemo iterating over a bunch of objects of indeterminate type and not having to use reflection. Instead, VisitorDemo just creates a Car object. The Visitor pattern isn't even useful in this scenario. Can we please get some better examples, and some better code samples? ThePedanticPrick 15:53, 12 April 2006 (UTC)[reply]
Ok, wait, I get it now. Car.accept passes the visitor to the accept methods of its components. I should have read more carefully. Nevertheless, this highlights the need for more clarity on the page. Also, it seems like there's more than one benefit to using this. There's the simulation of double dispatch, or what I called "no reflection needed", there's the ability to let an object handle its own component composition (also something we need to explain more clearly), and what BenFrantzDale describes below, the ability to decouple the function from the objects. He also goes on to describe something I don't fully understand yet, not being a graphics guy. ThePedanticPrick 19:27, 12 April 2006 (UTC)[reply]


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

The use described in Design Patterns is to move a higherarchy of methods into one place so that adding more such methods doesn't get out of hand. For example, if you have objects that will be drawn on the screen, you could have a 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.
Furthermore, if you have objects in scenegraph, you might want to draw them in different orders depending on the nature of the drawing context. For example, in OpenGL you might want to draw all brick-textured objects together to avoid excess context switching. The OpenGL visitor could collect a list of things to draw, sorted by texture usage, and only then would you draw the scene. This could not be accomplished easily with a simple recursive draw() method. —BenFrantzDale 20:25, 28 November 2005 (UTC)[reply]

UML

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)[reply]

please post it here so that we can discuss it :-) MatthieuWiki 17:26, 13 July 2007 (UTC)[reply]

Examples

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)[reply]

Where is it?

How about a more realistic example...?

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)[reply]

You might want to take a look at "Visitor Combination and Traversal Control" by Joost Visser - it specifically addresses visitor reuse and traversal strategies. 129.34.20.19 14:22, 29 June 2006 (UTC)[reply]
The key is that it gives you double dispatch. This essentially allows you to add virtual methods to classes that already exist. As a result, you get the power of virtual methods without having to add bloat to the classes. Plus it localizes a particular algorithm to one class rather than scattering it across classes.
For example, suppose I have a scenegraph with heterogenious objects that I want to draw. One way to draw this would be to have each object inherit some 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.)
In contrast, using the visitor pattern the OpenGL drawing functions would all be in one file, the DirectX functions in another file, and adding another drawing mode would simply be a matter of adding a third file.
Does that help? —Ben FrantzDale 22:25, 27 July 2006 (UTC)[reply]
Yes, that tells me a lot more about what one is supposed to gain from the pattern. I'm used to languages that have multimethods anyway, which was part of why I didn't get it.
I do feel compelled to point out that realistically, it's unlikely one would want a third 3D API, but the separation you describe is definitely a good thing.
Thanks. Dan Knapp 03:50, 8 November 2006 (UTC)[reply]

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)[reply]

Multimethod

Multimethod is a more general term for "double dispatch"

Car class in example is wrong?

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).[reply]

I agree with the above comment. The responsibility of a visitable object is to provide navigation to sub-components. A visitor would only be interested in adding extended functionality to individual nodes and should not be aware of how the nodes are linked. This is the responsibility of the aggregated object itself. --Pav007 11:53, 14 March 2007 (UTC)[reply]
I don't have Patterns in front of me, but I believe it can go either way. —Ben FrantzDale 12:05, 14 March 2007 (UTC)[reply]
It does seem to contradict the article though, which says: "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". Now, this implies that things can be different (needs clarification, by the way), but one would hope that the example should demonstrate the "simplest version" anyway. So i'm going ahead and fixing it. -- int19h 17:24, 15 March 2007 (UTC)[reply]

Duplicate examples in different languages

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)[reply]