GURU Of THE WEEK Terms 14: The relationship between classes (Part 1)

zhaozj2021-02-08  508

Gotw # 14 Class Relationshipships Part I

Author: Herb Sutter

Translation: Kingofark

[Declaration]: This article takes the Guru of The Week column on www.gotw.ca website, and its copyright belongs to the original person. Translator Kingofark translated this article without the consent of the original person. This translation is only for self-study and reference, please read this article, do not reprint, spread this translation; people download this translation content, please delete its backup immediately after reading. Translator Kingofark is not responsible for people who violate the above two principles. This declaration.

Revision 1.0

GURU Of THE WEEK Terms 14: The relationship between classes (Part 1)

Difficulty: 5/10

(How is your object-oriented design? This Terms will describe a mistake in which many programmers have made so far - oh, of course, is about the design of the class)

[problem]

Web applications generally have two different Communication sessions, each of the Communication Session, with its own specific message protocol (Message Protocol). Of course, these two protocols have similarations, such as some arithmetic operations and some messages (Message) may be the same. Thus, when the programmer wants to encapsulate some calculation operations and messages in the BasicProtocol class:

Class BasicProtocol / *: possible base classes * / {

PUBLIC:

BasicProtocol ();

Virtual ~ BasicProtocol ();

Bool Basicmsga (/ *...*/);

Bool Basicmsgb (/ *...*/);

Bool Basicmsgc (/*...*/);

}

Class Protocol1: Public BasicProtocol {

PUBLIC:

Protocol1 ();

~ Protocol1 ();

BOOL DOMSG1 (/ *...*/);

BOOL DOMSG2 (/ *...*/);

BOOL DOMSG3 (/ *...*/);

BOOL DOMSG4 (/ *...*/);

}

Class Protocol2: Public BasicProtocol {

PUBLIC:

Protocol2 ();

~ Protocol2 ();

BOOL DOMSG1 (/ *...*/);

BOOL DOMSG2 (/ *...*/);

BOOL DOMSG3 (/ *...*/);

BOOL DOMSG4 (/ *...*/);

BOOL DOMSG5 (/ *...*/);

}

The member function in the code can implement some necessary operations by a function of the base class, but the true transfer operation is still implemented by themselves. Each class in the code is of course possible to include other members. Here we assume that all members related to the problem are already in the code we see.

Try to analyze this design in the code. Is there anything you need to modify? If so, explain why you need to modify it.

[answer]

This Terfection indicates a hidden danger that is generally existed in the design of the relationship between "classes". We first recall the code given above: Protocol1 and protocol2 These two classes derived from the PUBLIC-based class BasicProtocol; base class BasicProtocol completed some specific tasks.

The key to this question is the following sentence:

The member function in the code can implement some necessary operations by a function of the base class, but the true transfer operation is still implemented by themselves.

The problem came out: the code is clearly depicted with "IS IMPEMENTED IN TERMS OF" relationship. [Translation 1] In C , this relationship means "Private Inheritance" or "MemberShip". But unfortunately, many people have always thought that this relationship means "public inheritance". They confuse the Implementation Inheritance and Interface Inheritance (inheritance). In fact, Implementation Inheritance and Interface Inheritance are completely different, and people's confusion for this is from the problems we have to discuss in this Territor. [Translation 2] [Note 1]

The following few clues describe the problem here:

1. The BasicProtocol class does not provide a virtual function (which is not included here; the problem with the destructor will be mentioned in the following description). [Note 2] This means that it is not ready to be used in Polymorphically, and this means that there should be no public inheritance mechanism.

2. There is no protected function or protected member in the BasicProtocol class. That is to say, there is no "DeriVation Interface" in the class, which means that BasicProtocol should not be inherited in any way - whether it is in a PUBLIC mode or a private method.

3. BasicProtocol encapsulates some specific operations, but it does not implement your own transmission operation like it is derived. That is, the BasicProtocol object is not as used as the object of its derived class, nor is it useful as the object of its derived protocol class (USABLE-AS-A). Public inheritance should only be molded (also the only one) relationship: 即 IS-a (one) relationship on a real interface, it follows Liskov Substitution Principle (Riskov Replacement principle). [Translation 3] To clearly, I usually refer to it called Works-Like-a (like something like something) and usable-as-a (useful as something as something). [Note 3]

4. These derived classes only use the public interface of BasicProtocol. That is to say, they did not have any additional benefits due to derived from BasicProtocol. We can use an auxiliary BasicProtocol object to complete their assumptions.

In this way, we need some modifications to the code:

First, since it is not intended to inherit the BasicProtocol as the base class during design, it is unnecessary, and it should be removed. Second, BasicProtocol should be changed to a name such as MessageCreator that makes it unlealed to mislead others, causing an understanding of errors.

Then, after the above modification, which way should it use to mold "Is Implement in Terms of (according to something according to something)"? Is the private inheritance (private inheritance) method or MEMBERSHIP (member belt)?

The answer to this question is easy to remember:

[Learning Guidance]: When the mold is "IS IMPLEMENTED IN TERMS OF" "" "" "" "" " When you don't have to form inheritance relationships, you need to access the protected member, or if you need override virtual functions, you will use private inheritance. Never use the public inheritance (public inheritance) method because only the code is to be multiplexed.

Using Membership (member home) mode, we can better think of some questions, because this time the user has a normal client, only to the user, etc. (Used Class The public interface is accessed. So, please use Membership (member home) mode, so you will find that your code is simple, readable, it is easier to maintain. Simply put, your code will save more!

***************************************************

[Note 1]: It happened that those programmers who were easy to commit to this mistake often generated a deep inheritance level. Based on the following two reasons, this greatly increases the burden on maintenance work:

l Add unnecessary complexity

l Forced users to learn many unnecessary class interfaces, even if they just want to use a particular derived class.

In addition, since unnecessary VTABLE is added, and the indirectibility of the class of VTABLE is not required, the use of the memory is also affected by the use of memory. If you find that you have often generated deep inheritance level, then you should examine your design method, see if you have developed this bad habit. In fact, the deeper hierarchy is rarely used, even basically not a good thing ... If you don't believe, and still think "If there are not many inheritance, you can't be an object", then you should Go see the standard library - that is a good example, enough to explain that you want to be wrong.

[Note 2]: Even if the BasicProtocol itself is also derived from another class, the conclusions here are constant, because BasicProtocol does not provide any new virtual functions. If a base class with a BasicProtocol provides a virtual function (Virtual function), it is only that that the base class wants to be used in the PolyMorphically (polymorphic) method, not BasicProtocol; so we are too much It should be inherited from that base class (rather than inheriting from BasicProtocol). [Note 3]: Indeed, when you inherit in the public method, if the base class has both the interface you need, there is some specific implementation, then some of them will come with . This effect can almost always be avoided, but it does not always need to take a special pure "One Responsibility Per Class".

[Translation 1]: For "Is Implement In Terms of", see Scott Meyers "Effective C " Terms 40 and Terms 42.

[Translation 2]: Please see the Scott Meyers "Effective C " Terms Terms 36: Difference Interface Inheritance and Implement Inheritance (Implement Inherit).

[Translation 3]: About Liskov Substitution PrinciPle, please see the discussion related to Mr. Houjie's Scott Meyers "Effective C " Terms 35.

(Finish)

转载请注明原文地址:https://www.9cbs.com/read-380.html

New Post(0)