When learning the design model from the very beginning, there is a concept. Visitor is a chicken pattern. because the visitor mode has a high requirement on the stability of the class structure, I feel that it is rarely used in real life. (In reality, it is always possible, or it is always intended to add a virtual function interface ).
Of course, visitor is more than the current issue. Another prominent problem is circular dependency. this is an embarrassing problem for C ++, or oo. It is also mentioned in <C ++ coding standard>"22nd to minimize the definition dependency. Avoid circular dependency
"The example is the visitor.
Now let's unveil the figure of the visitor. First, let's look at the UML diagram of the traditional visitor.
We can clearly see the Dependencies from this figure:
1. docelement as the base class of the element depends on the base class of docelementvisitor
2. docelementvisitor depends on all derived classes of docelement, including paragraph and rasterbitmap.
3. The Derived classes of all docelement certainly depend on the docelement class!
Such a ring appears !!! Therefore, the intuitive idea here is that this mode is somewhat less than make sense. in this chapter, the author is happy to share his acyclic visitor. note that this acyclic does not loop.
Of course, before proceeding to the implementation in the book, let's take a look at how common implementations are. robert C. martin helped us find the crux and gave a solution. in fact, our intuitive idea is that this visitor can not contain all the interfaces of the visit (element & Ele) (derived class), or it is very good if it does not appear only in the visitor class! The solution here also uses this idea.
The solution here is that docstatus is not inherited from docelementvisitor, but also from rasterbitmapvisitor and paragraphvisitor. That is to say, when paragraph accept, it converts visitor & into paragraphvisitor, of course, you can easily enable paragraphvisitor to access the visitparagraph interface of docstats (because the paragraphvisitor function is a pure virtual function ). in this way, we found the corresponding docstats function in a large circle. at least the current structure eliminates the cycle dependency. We can see that docelementvisitor does not need any specific visitorxxx interface, but is just a declaration of pure virtual destructor.
The implementation of an acyclic visitor template is based on the following idea:
// Visitable part <br/> template <typename r = void> <br/> class basevisitable <br/>{< br/> Public: <br/> typedef R returntype; <br/> virtual ~ Basevisitable () {}< br/> virtual R accept (basevisitor &) = 0; <br/> protected: <br/> template <class T> <br/> static returntype acceptimpl (T & visited, basevisitor & guest) <br/> {<br/> // apply the Acyclic visitor <br/> If (visitor <t> * P = <br/> dynamic_cast <visitor <t> *> (& guest )) <br/>{< br/> return p-> visit (visited); <br/>}< br/> return returntype (); <br/>}< br/>}; <br/> # define define_visitable ()/<br/> virtual returntype accept (basevisitor & guest) /<br/> {return acceptimpl (* This, guest );}
This protected function can be called directly only when the derived class has a macro definition of define_visitable.
Another thing worth noting is the last return returntype (); In this article, we will not expand some policies of the catchall template, it seems a bit too much to say so much for a model that doesn't like and is not very successful :)