Visitor pattern - adding new ConcreteElement class

2019-03-06 09:04发布

I read a book about the visitor pattern. It gives the same class diagram as in the oodesign's website.

It says that adding new ConcreteElement classes is hard. But I didn't understand why. As I understood, the Concretevisitor defines the set of operations, which have to be used by the concreteElement. So when I add a new element, which has the same operation I defined earlier, I don't need to add anything (just the ConcreteElement itself). If I add a new element, which doesn't have the same operations I defined earlier in the visitors, I need to add a new visitor. But this I have to do in any design pattern.

4条回答
不美不萌又怎样
2楼-- · 2019-03-06 09:37

Essentially, visitor pattern is kind of data manipulator, it will

  • Traverse among elements following some rules
  • Do some calculation and manipulation with the data those elements provide

In one word, visitor pattern will extend the system functionality, without touch the element class definition.

But does this mean the visitor class must be revised if new concrete element class is added? It depends, I believe, on how the visitor pattern is designed and implemented.

If separate all the visit methods of visitor into visit functors, and dynamically bind the them together, then it might be easier when extending the how system, for both visitor and visitee.

Here is an implementation of visitor pattern I wrote several years ago, the code is a bit old and not well polished, but somehow works :)

https://github.com/tezheng/visitor

查看更多
放我归山
3楼-- · 2019-03-06 09:48

This came up in an SO question just recently. To quote myself from this question, and more specifically the discussion

The reason a precondition of not changing the set of entities (classes you visit) is because it forces you to implement a new VisitXYZ in each concrete visitor. But I never took much stock in that reasoning becasue if you are supporting a persistance visitor, and a text search visitor, and a print visitor, and a validation visitor and you go and add a new entity you are going to want to implement all that functionality anyway. The visitor pattern (with a common base class) just lets the compiler find the ones you forgot to implement for you.

So yes it is often said that its hard to implement addition conrete elements (or entities), but in my opinion it is hogwash.

查看更多
不美不萌又怎样
4楼-- · 2019-03-06 09:51

If you add a new concrete element, then all of your visitor classes will need to add a new visit method for the new element. If you didn't use visitors, you would have to add the equivalent methods to your new concrete element anyway.

But adding a new method to each your visitors may be harder than adding the equivalent set of methods to a new element class. The reason is that visitors often need to traverse the element tree structure and may need to manage its own state data as it does so. Adding a new visit method may require modifying that state data which involves thinking about how the new method interacts with existing visit methods for other elements.

It may be simpler to add the equivalent methods to your new element class if you didn't have visitors because you will only need to worry about the internal state of the new concrete element which is more cohesive.

查看更多
劳资没心,怎么记你
5楼-- · 2019-03-06 10:00

Well, you have to extend all your visitors.

You have a caller, some elements that need to be visited, and an element - the visitor - that does the processing of the individual elements. Your goal is to keep the implementation of the elements and the caller fixed, and extend functionality via new visitors.

Usually you have a lot of the concrete visitors. If you add a new type of element to be processed, you will need to change all the concrete visitors to take this into account.

Why?

well, imagine that the caller is "Factory", and you have the elements "Car" and "Bike".

For operation "Paint" you have to have the methods

void process(Car c); // Paint a car
void process(Bike b); // Paint a bike

Likewise for operations "Assemble", "Package", "Wash" etc.

If you add an element "Scooter", all the operations have to be extended with a new method

void process(Scooter s); // Handle a Scooter

This is a bit of work. Also you may hit the isse where the element you add is so different from the others that you canøt easily fit them to the operations.

Wikipedia (http://en.wikipedia.org/wiki/Visitor_pattern) says

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

That's a pretty abstract way of saying what I try to say above. Usually you'd add these methods to the elements, but if you can't you have to add the methods to somethign else, and pass that along to do the processing. This is a bit of extra work, but may be worth it, if the situation merits it.

查看更多
登录 后发表回答