Why visitor pattern




















Visitor design pattern is one of the behavioral design patterns. It is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.

The visitor pattern consists of two parts: a method called Visit which is implemented by the visitor and is called for every element in the data structure visitable classes providing Accept methods that accept a visitor UML Diagram Visitor design pattern Design components.

Advantages : If the logic of operation changes, then we need to make change only in the visitor implementation rather than doing it in all the item classes. Adding a new item to the system is easy, it will require change only in visitor interface and implementation and existing item classes will not be affected.

Disadvantages : We should know the return type of visit methods at the time of designing otherwise we will have to change the interface and all of its implementations. We need many unrelated operations, and don't want to put different operations into the same class. This is indicated by the Single Responsibility Principle. The drawback of the Visitor Pattern is that we have now lost the ability to add new Animal subclasses. We would have to add them to the AnimalVisitor interface as well, and that would break all existing visitors.

In practice, the visitor pattern is often used in compilers. Here, the syntax of a program is usually represented through a tree data structure, where each element in the tree may have a different type. Different parts of the compiler do wildly different stuff with this tree: one part pretty-prints the code. One part optimizes the code. Another part compiles the code to another languages, and a further visitor could be an interpreter.

All these unrelated operations can be written as visitors, so that the definitions of the various types in the trees contains nothing more than the data fields, and a bit of visitor boilerplate. Sign up to join this community. The best answers are voted up and rise to the top. Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams?

Learn more. Understanding the need of Visitor Pattern Ask Question. Asked 5 years ago. Active 5 years ago. Viewed 7k times.

Improve this question. I would appreciate to mention the reason of down vote. It'll help me and others to improve the quality of question next time. That's not the visitor pattern. Yes it is not. It just implemented in visitor pattern way which is wrong. I had created a gist for visitor pattern example as per accepted answer. It doesn't know what the visitor performs and so no idea about whether and how to change the Piece state.

A way to identify the visitor would be to perform a post processing in Piece. It would be a very bad idea as it would create a high coupling between Visitor implementations and Piece subclasses and besides it would probably require to use trick as getClass , instanceof or any marker identifying the Visitor implementation. Contrary to some other behavioral design patterns as Decorator for example, the visitor pattern is intrusive.

We indeed need to modify the initial receiver class to provide an accept method to accept to be visited. We didn't have any issue for Piece and its subclasses as these are our classes. In built-in or third party classes, things are not so easy. We need to wrap or inherit if we can them to add the accept method. The pattern creates multiples indirections. The double dispatch means two invocations instead of a single one :.

And we could have additional indirections as the visitor changes the visited object state. It may look like a cycle :. Apply the same computation to several data structures, without changing the code which implements the computation. Please have a look at an article I've written about this. As Konrad Rudolph already pointed out, it is suitable for cases where we need double dispatch.

Just to make the example relevant for our discussion, lets also assume that the APIs exposes by Intel radio are different from the ones exposed by Broadcom radio. So depending upon Right type of device and Depending upon right type of Bluetooth radio , it can be switched on by calling appropriate steps or algorithm. Now, Visitor pattern can be applied to this problem. The visitor takes the instance reference as input, and implements the goal through double dispatch.

Here is how the set up will look like -. Here you have different container classes for Pill :. As you see in above, You BilsterPack contain pairs of Pills' so you need to multiply number of pair's by 2. Also you may notice that Bottle use unit which is different datatype and need to be cast. Notice that above code violate Single Responsibility Principle. That means you must change main method code if you add new type of container.

Also making switch longer is bad practice. You moved responsibility of counting number of Pill s to class called PillCountVisitor And we removed switch case statement. That mean's whenever you need to add new type of pill container you should change only PillCountVisitor class.

Also notice IVisitor interface is general for using in another scenarios. That mean's: Every pill container allow the PillCountVisitor visitor to see their pills count. He know how to count your pill's. IuseVisitor you see real scenario in which you can not use polymorphism the answer to follow Single Responsibility Principle. In fact in:. So it is better to use visitor pattern to overcome the problem. He summarizes the problem:. Compound objects often have a complex structure, composed of individual elements.

Some elements may again have child elements. An operation on an element visits its child elements, applies the operation to them, and combines the results. However, it is not easy to add new operations to such a design. The reason it's not easy is because operations are added within the structure classes themselves. For example, imagine you have a File System:. You could add functions to each class in the FileSystem to implement the operations and people have done this in the past as it's very obvious how to do it.

The problem is that whenever you add a new functionality the "etc. At some point, after some number of operations you've added to your software, the methods in those classes don't make sense anymore in terms of the classes' functional cohesion. The Visitor Pattern like many design patterns was born from the pain and suffering of developers who knew there was a better way to allow their code to change without requiring a lot of changes everywhere and also respecting good design principles high cohesion, low coupling.

It's my opinion that it's hard to understand the usefulness of a lot of patterns until you've felt that pain. Explaining the pain like we attempt to do above with the "etc.

Understanding patterns is hard for this reason. Visitor allows us to decouple the functionalities on the data structure e. The pattern allows the design to respect cohesion -- data structure classes are simpler they have fewer methods and also the functionalities are encapsulated into Visitor implementations.

This is done via double-dispatching which is the complicated part of the pattern : using accept methods in the structure classes and visitX methods in the Visitor the functionality classes:. This structure allows us to add new functionalities that work on the structure as concrete Visitors without changing the structure classes. For example, a PrintNameVisitor that implements the directory listing functionality, and a PrintSizeVisitor that implements the version with the size.

We could even have a visitor that displays my directory tree using a graphical language such as DOT , to be visualized with another program. As a final note: The complexity of Visitor with its double-dispatch means it is harder to understand, to code and to debug.

In short, it has a high geek factor and goes agains the KISS principle. In a survey done by researchers, Visitor was shown to be a controversial pattern there wasn't a consensus about its usefulness.

Some experiments even showed it didn't make code easier to maintain. In my opinion, the amount of work to add a new operation is more or less the same using Visitor Pattern or direct modification of each element structure. Also, if I were to add new element class, say Cow , the Operation interface will be affected and this propagates to all existing class of elements, therefore requiring recompilation of all element classes.

So what is the point? For example if you define a new operation without changing the classes of the elements on which it operates.

Quick description of the visitor pattern. The classes that require modification must all implement the 'accept' method. Clients call this accept method to perform some new action on that family of classes thereby extending their functionality. Clients are able to use this one accept method to perform a wide range of new actions by passing in a different visitor class for each specific action.

A visitor class contains multiple overridden visit methods defining how to achieve that same specific action for every class within the family. These visit methods get passed an instance on which to work.

I didn't understand this pattern until I came across with uncle bob article and read comments. Consider the following code:. Each time you have new Employee type you will have to add if with type check. And if you won't you'll never know that at compile time. And if you forget to implement visit it won't compile:.

The magic is that while v. Visit this looks the same it's in fact different since it call different overloads of visitor. At the same time, adding the "Walk" method generate new questions.

What about "Eat" or "Sleep"? Must we really add a new method to the Animal hierarchy for every new action or operation that we want to add? That's ugly and most important, we will never be able to close the Animal interface. So, with the visitor pattern, we can add new method to the hierarchy without modifying the hierarchy!

How do you get around this? The visitor pattern allows you to extend the interface of the primary type by creating a separate class hierarchy of type Visitor to virtualize the operations performed upon the primary type. Visitor implements "double dispatch". OO messages routinely manifest "single dispatch" - the operation that is executed depends on: the name of the request, and the type of the receiver.

In "double dispatch", the operation executed depends on: the name of the request, and the type of TWO receivers the type of the Visitor and the type of the element it visits. The implementation proceeds as follows.

Create a Visitor class hierarchy that defines a pure virtual visit method in the abstract base class for each concrete derived class in the aggregate node hierarchy. Each visit method accepts a single argument - a pointer or reference to an original Element derived class.

Each operation to be supported is modelled with a concrete derived class of the Visitor hierarchy. The visit methods declared in the Visitor base class are now defined in each derived subclass by allocating the "type query and cast" code in the original implementation to the appropriate overloaded visit method.

Add a single pure virtual accept method to the base class of the Element hierarchy. Each concrete derived class of the Element hierarchy implements the accept method by simply calling the visit method on the concrete derived instance of the Visitor hierarchy that it was passed, passing its "this" pointer as the sole argument.

Everything for "elements" and "visitors" is now set-up.



0コメント

  • 1000 / 1000