Dialogue with prawns: Recognizing the design mode - Template Method / Visitor [Translator Press] This article is compiled according to the published in CUJ EXPERT Forum. C / C User's Journal is currently the best magazine, which is currently the best C / C language, especially after C Report is closed, Cuj's status is more prominent. CUJ EXPERT Forum is the online technology column hosted by CUJ, which brings together the technical and essays of top experts in the C community since October 2000, and freely public release, exciting, is a non-missed information of each C / C learner. The Conversation Series hosted by Jim Hyslop and Herb Sutter is a must-have bise column, which is a must-have quality column in the form of a humorous dialogue, which is widely praised in the C community. The translator specially selection two articles in two design patterns, introduces you to everyone. The classic works in design patterns are GOF's Design Patterns. But the book has a shortcoming, not understanding. From the style, the book is said to be a tutorial model for the learner, but it is better to say that the academic report will be seen from the academic people, and rigorous and more vivid. This includes the author of the book and the masters like Bjarne Stroustrup never say. In fact, Design Pattern is not necessarily unknown. Through vivid examples, a medium-level C learner can fully master basic usage, use it in its own programming practice to get immediate effect. These two articles are very good examples. This paper has made many deletions and modifications in the premise of ensuring technical integrity, so that the article is more compact. -------------------------------------------------- -------- Character introduction: I - a C programmer pursuing upward, still in the trial period, smart but experience. Wendy --- The technology of the company is sitting in the compartment next to me, C prawns, the most great thing is that she is a woman! She is good, it is a bit thin, I really worship her for her. -------------------------------------------------- -------- I. Virtually Yours - Template Method Mode I am studying a class written by Wendy. That is a abstract base class she written for this project, and my job is to give a concrete class from the middle school. The PUBLIC part of this class is like this: Class Mountie {
PUBLIC:
Void Read (std :: istream);
Void Write (std :: ostream);
Virtual ~ mountie (); very normal, Virtual Destructor indicates that this class is intended to be inherited. Then look at its protected section: protected:
Virtual Void Do_read (std :: istream);
Virtual void do_write (std :: ostream);
It is just a kung fu, I know the trend of Wendy: She is using the template method mode. Public member functions Read and Write are non-virtual, they are definitely calling the protected section DO_READ / DO_WRITE virtual member function to complete the actual work. Ah, I am just floating for my own progress! Ha, Wendy, this time you can't help me, what is the trick? Despite relying on the horse ... Suddenly, the smile is solidified on my face, because I saw its private section: private: Virtual st: string classid () const = 0;
what is this? A private pure sequence function, can you work? I stood up, "Wendy, your mountie class doesn't seem to work yeah, it has a private virtual function." "You tried?" She didn't lift it. "Well, it is okay, but think about it. How can my derive class Override your private function?" I muttered. "Hey, you are very confirmed!" Wendy's voice is very soft, "How do you always do this? It's okay, these months follow me, you haven't learned something? Small vegetables." Okay ... "Small Rookie, you all have forgotten, the access control level is not a virtual basis with a function. Judging a function is the last step of dynamic binding or static binding is the final step of the function call parsing. Standard 3.4 and 5.2.2. "I am completely under the wind and have to take interference tactics. "Well, even if you say it, I still don't understand. Why do you set it up to private?" "I and ask you, if you don't want to make a member function in a class, how should you handle? "" Of course, set it to private, "I replied. "So you go to see my Mountie class implementation, especially the implementation of the Write () function." I can't escape the whisper of Wendy, I turned to search on my screen, very fast, I found : Void Mountie :: Write (std :: ostream & dudley) Const
{
Dudley << ClassID () << std :: endl;
Do_write (DUDLEY);
} Hey, the recent cartoon film is really too much, actually made such a low-level mistake. Still always admitted: "Well, I understand .classID () is a detail of implementation, used to save the object, the type of iconic class, the derived class must overwrite it, so it must be pure. But since it is To achieve details, it should be set to private. "" This is almost, the small rookie. "The prawn nodded." Now give me the do_read () and do_write () is protected? "This problem is not difficult?" I organized a try to answer: "Because the derived class object needs to call the implementation of these two functions to read and write the base class object." "Very good," prawn is almost satisfied, "But you explain again Explain why I don't set them as public? "I feel much now:" Because it is necessary to do in a specific way, you must write the type information, then use the object. Information is written, when reading, the module responsible for generating an object first can know what type of object to be read, and then read object information from the stream. "" Smart, my little rookie! "Wendy pauses," Just learn how to learn foreign speaking, learning C is not only mastering grammar, but also must master a lot of usa. "" Yeah, I am going to read Coplien's book ... " [Translator Note: James Coplien 1992 classic book Advanced C Programming style and idioms] prawn waved her hand, "Calm, small rookie, I don't mean the book of the prophet Coplien, I refers to some kind The structure behind the structure. For example, a class of Virtual Destructor is equivalent to telling you: 'Hey, I am a polymorphic base class, to inherit me!' And if a class DEStructor is not virtual, it is quite So, 'I can't be used as a polymorphic class, seeing on the old days, don't inherit me.' "" The same, the visiting control level of the Virtual function has implicit. A protected virtual function tells you : 'You wrote the derived class, oh, but it is necessary to call my implementation.' And a private virtual function is said: 'Derive class can be overwritten, or you can not overwrite me, with you. But you don't You can call my implementation. '"I nodded, telling her that I understand, then ask:" So Public Virtual Function? "" Do not use public virtual function. "She picked up a pen and wrote the following. Code: Class HardtoExtend {public: Virtual VoID f ();}; void hardtoextend :: f () {// perform a specific action} "Suppose you release this class. When writing the second edition, the demand changes, you must use Template Method. But this is impossible, do you know why? "Hey, this ... I don't know." "" Both possible ways. First, transfer F () implementation code into a new function, then set f () itself to non-virtual: class hardtoextend {
// POSSIBLY PROTECTED
Virtual void do_f (); public:
Void f ();
}
Void HardtoExtend :: f ()
{
// pre-processing
DO_F ();
// post-processing
}
Void HardtoExtend :: DO_F ()
{
// Perform a specific action
}
However, your original derived class is an attempt to Override function f () instead of do_f (), you must change all derived class implementation, as long as you miss a class, your class level will be infected with the prophet Meyers 'Practical division of schizophrenia'. "[Translator Note: See Scott Meyers, Effective C , Item 37, absolutely don't redefine inherited non-virtual functions]" Another way is to move f () to the Private area, introduce a new Non-Virtual Function: "Class HardtoExtend
{
// POSSIBLY PROTECTED
Virtual void f ();
PUBLIC:
Void Call_f ();
}; "This will result in countless problems. First, all customers have attempt to call f () instead of call_f (), now their code can not be compiled. What is even, most of the derived classes Put F () in the public area, which directly uses derived class users to access the details you want to protect. "" Treat virtual functions To treat data members, set them to Private until design requirements Use more relaxed access control to adjust. To know by private into public easy, it is difficult by public into private! "[Translator Note: The idea expressed in this article has certain disruptive, because we are too easy to be based on the base class In setting the public virtual function, Java is even specifically established for this practice, and now it is not good! I can't accept it for a time. But carefully understand the author's meaning, he is not generally opposing public Virtual Function, just gives the above principles in the background of Template Method. Although this principle is also worth considering in the general design, the main application field is still in the Template Method mode. Of course, Template Method is a very useful and common mode, so it has also determined the principles proposed in this article. ] --------------------------------------------------- --------------- ii. Visitor model I am being distressed for a design problem. The trial period is over, I hope that I will solve this problem to prove my progress. Everyone remembers its first job, you should also know how important it is done at this time! I have seen other new employees who have not been frying the trial period, because they don't know how to deal with the prawns ..., don't misunderstand, I am not saying that she is not good, she is my best. Programmer, it is a bit thin. Now I worship her as a teacher, not doing anything, because I hope to reach the height of her. I want to add a new virtual function in a class hierarch, but this class is maintained by another part of people, others can't touch: Class Personnel
{
PUBLIC:
Virtual void pay (/ *...*/) = 0;
Virtual void promote (/ *...*/) = 0;
Virtual Void Accept (Personnelv &) = 0; // ... Other functions ...
}
Class officer: public personnel {/ * override virtuals * /};
Class Captain: Public Offector {/ * Override Virtuals * /};
Class first: public officer {/ * Override Virtuals * /}; I want a function, if the object is the captain, if it is a big pair (first officer). Virtual Function is a solution, declare it in Personnel or Office, and override it in Captain and First. Worse, I can't add such a virtual function. I know that I can give a solution with RTTI: Void F (Offer & O)
{
IF (Dynamic_Cast
/ * Do One Thing * /
Else IF (Dynamic_cast
/ * Do Another Thing * /
}
int main ()
{
Captain K;
First S;
f (k);
f (s);
} But I know that using RTTI is the behavior of the company's code standard, I said to myself: "Yes, although I didn't like RTTI before, but this time I had to change the view to it. I am obvious, in addition to using RTTI, in addition to using RTTI, There is no way. "" Any questions can be solved by adding an indirect hierarchy. "I jumped up, it was the voice of prawns, she didn't know when I ran to my back," Ah, you are scared. " I jump ... What did you say? "" Anyone ... "Yes, I listened to it," I don't know where the courage, I dare to interrupt her. "I just don't know you." From which it came out. "In fact, this is just a panic of my heart." "Ha, forget it, small rookie," prawn is oblique to see me, "You think I don't know what you think!" She raised his voice in eight degrees, staring at me, "those poor C language The disciples will use the switch statement to handle different object types. You see: "/ * a not-atypical c program * /
Void F (Struct Somestruct * S)
{
Switch (S-> Type) {
Case apple:
/ * Do One Thing * /
Break;
Case Orange:
/ * Do Another Thing * /
Break;
/ * ... etc. ... * /
}
"When these people learn Stroustrup's C language, the most important thing is to learn how to design a class level." "Yes," I interrupt her again, I can't wait to let Wendy understand, I still have two mesaka, "They should design a FRUIT base class, derive apple and orange, use the Virtual Function to make specific things." Very good, small rookie. C language disciples usually have changed. However, you should know that you add an indirect hierarchy by using the Virtual Function. "She puts down," Do you need it is a new virtual function? " "Yes it is. But I have no power to do so. "" Because you have no right to modify classes, right! " "You finally learned, we can't move it." I don't know which guy is designed by this dead class level ... "I screamed." It was I designed. "Ah ..., really?" ! This, 嘿 ... ", I am very embarrassing." This level must be very stable because there is a cross-platform issue. But its design allows you to add new Virtual Function without having to worry about RTTI. You can solve this problem by adding an indirect hierarchy. I would like to ask, what is Personnel :: accept? "" Well, this ... "" This class implements a model, but unfortunately the name of this mode is not very good, it is a PNP called Visitor mode. "[Translator Note: PNP, Poor-named Pattern, does not start the model of the name]" Ah, I just read Visitor mode. But that is just the mode that allows several objects to be iteted to access each other, isn't it? "She sighed," this is a popular mistroduction. That V, I think it is Visitor, it is better to say that Virtual is better. The most important use of this PNP is to add new virtual functions to existing classes without changing the class level. First come and see the details of the ACCEPT implementation of Personnel and its derived class. "She picks up the pen and write: void personnel :: accept (personnelv & v) {v.visit (* this);}
Void officer :: Accept (Personnelv & V)
{v.visit (* this);
Void Captain :: Accept (Personnelv & V)
{v.visit (* this);
Void First :: Accept (Personnelv & V)
{v.visit (* this);} "The base class of Visitor is as follows:" Class Personnelv / * isitor * /
{
PUBLIC:
Virtual void Visit (Personnel &) = 0;
Virtual void Visit (Offer &) = 0;
Virtual Void Visit (Captain &) = 0;
Virtual Void Visit (first &) = 0;
}; "Ah, I remember it. When I want to use the Personnel class hierarchy, I just call Personnel :: Accept (MyVisitorObject). Because Accept is a virtual function, my myvisitorObject.visit () will be correct Object type calls, according to the overloaded rule, the compiler will pick the most appropriate Visit to call. Is this unameter of adding a new virtual function? "" Yes, the small rookie. As long as the class level supports Accept, We can add new virtual functions without changing the level. "" Well, I know what to do now ", I wrote: Class Dosomething: public personnel {
PUBLIC:
Virtual Void Visit (Personnel &);
Virtual Void Visit (OFFICER &);
Virtual Void Visit (Captain &);
Virtual Void Visit (First &);
}
Void Dosomething :: Visost (Captain & C)
{
FemaleguestStarispresent)
C.TurnonCharm ();
Else
C.startfight ();
}
Void DOSMETHING :: Visit (first & f)
{
f.raiseeyeBrowatcaPtainsbehavior ();
} void f (Personnel & P)
{
P.Accept (DOSMETHING ()); // is equivalent to p.DOSMETHING ()
}
int main ()
{
Captain K;
First S;
f (k);
f (s);
} The prawn smiled satisfied, "Maybe this mode is more so good, but unfortunately, the world is often not satisfied." [Translator Note: I made a certain amount of deletion in this article. There is a little more discussion in the original text, and LINK has two technical articles. ]