The main purpose of this article is to introduce the high-quality design principles for some classes and interfaces. These principles should not only ensure that the classes or interfaces designed and implemented have high-quality code, but also, more importantly, they should
Make code updates and maintenance as far as possible without affecting the customer's activities, that is, to maintain binary code compatibility (Binary
Compatibility) and source code compatibility
Compatibility ). I hope these guidelines will help my friends who have just entered the industrial field from school to adapt to higher-standard programming requirements as soon as possible and improve their design capabilities as soon as possible.
This article takes the design of C ++ classes as the scope of discussion.
Overview
Object-Oriented Programming is very helpful for producing high-quality and easy-to-maintain code. The concept of object-oriented programming is built on three basic features: encapsulation, inheritance, and polymorphism. In C ++, class is a plane
The core and specific form of the concept of object-oriented programming. Class uses private members to embody "encapsulation", "inheritance" through direct inheritance or combination, and dynamic binding through virtual functions (dynamic)
Binding) represents "polymorphism ". The design quality of the class directly determines the quality of the entire system.
There are three principles for class design at the overall function layer:
· Single Responsibility Principle)
A class should provide only a single service as a whole. If a class provides a variety of services, it should be split. Otherwise, if a single function is assumed by several classes, these classes should be merged.
· Open/close Principle)
A well-designed class should be open to the expanded action while closed to the modified action. That is to say, this class should allow expansion, but cannot be modified. To expand functions, you should add new classes instead of modifying the code of the original class. New classes can be added not only through direct inheritance, but also through combination.
· Least Surprise Principle)
When you overload a function or subclass to implement a parent class virtual function, you should basically maintain the function originally expected. For example:
Class pet { Public: Virtual talk () = 0; };Class Cat: Public pet { Public: Void talk () {cout <"Miao ";} }; Class dog: Public pet { Public: Void talk () {biteowner ();} }; |
When implementing the virtual function talk, class dog does not output the dog bark as we expected, but bit the master. This should be avoided.
Interfaces and Implementations
In the system, there are two ways to observe a class. From the external or user perspective, we can see interfaces, and from the internal perspective, we can see implementation. Because the system must be constantly modified, the implementation will inevitably not stop
But the interface is required to be as stable as possible. The contradiction between the two must be avoided through a good design. The basic principle is to isolate the implementation details from the interface. The following lists the specific points:
· Minimal and complete Interface Design
Streamline the number of interface functions to make each function representative. The function just overwrites the class function. A minimal interface can simplify maintenance, increase potential code reusability, and reduce customer confusion,
The header file length and Compilation Time can also be reduced. When improving a function, you should use a function name like this to implement improvements and retain the original function. The corresponding descriptions should be provided in the Code annotations. New functions can be added, but old functions cannot be deleted.
Function.
· All member variables should be private
It is obvious that the public variable destroys encapsulation and the separation of interfaces and implementations. The protected variable may also allow the customer to write the inheritance class and rely on the implementation details of the parent class.
· Avoid function returning pointer or reference to member variables
This will also make the Customer Code dependent on the implementation details.
· Whether to disable the default functions generated by the compiler
These functions include the copy constructor and the value assignment operator (operator ).
= ). If we do not intend to define our own version rather than disable the default version, the Customer Code may call these functions without looking at them. Problems may occur when the implementation changes, such
Class has an additional heap memory pointer. If we allow object copying, it is safer to disable them and define a dedicated clone () function.
Compatibility)
Needless to say, compatibility is very important. One of the important reasons why intel and Microsoft are so successful is that their products, both hardware and software, are well compatible with old products. The same is true for code compatibility. It is hard to imagine that if a customer is dependent on your library product and constantly rewrites his code because of the update of your product, he will continue to use your product.
Code compatibility can be divided into binary compatibility and source code compatibility. Binary Compatibility means that the customer's compiled code can directly use the compiled code of different versions without re-compilation.
Source code compatibility means that if your code is updated, your code does not need to be modified, and you only need to recompile it to run properly. In C ++, interfaces are generally extracted from the header file and library binary code.
Therefore, any situation that may cause inconsistency between the library code and the old header file may damage binary compatibility, because the customer code must be re-compiled with the new header file.
Therefore, following several rules makes it easier for you to solve compatibility problems:
· Do not change the class size or the sequence of member variables
There are several aspects: do not increase or decrease member variables; do not modify the type of member variables; do not change the Declaration sequence of member variables; do not change the existence of virtual functions. Obviously, increasing or decreasing member variables will change the class size.
Small, And the header file needs to be updated, which may cause incompatibility with the customer code. Changes in the type may also cause changes in the class size. The access to member variables is generally determined by the compiler's offset.
The offset will change, compromising binary compatibility. The existence of virtual functions determines whether there are virtual function table pointers, which affects the class size and the sequence of member variables.
· Do not use the inline function
The inline function is declared in the header file and compiled in the client code. If the inline function accesses the private member and the member changes the order, the inline function is re-compiled, this compromises binary compatibility.
· Interface functions do not use virtual functions
The access to virtual functions is similar to the access to member variables. It is through the offset in the virtual function table. Changes to the virtual function order will affect the offset. Therefore, when conditions permit, avoid using public virtual functions. For example:
Class Picture { Public: Virtual void draw (); }; |
Should be changed
Class Picture { Public: Void draw (); PRIVATE: Virtual void dodraw (); };Void picture: Draw () |
· Do not change the order of interface functions
In many embedded systems, the Linked Library exposes interfaces through the exported function table to save space. In this case, access to interface functions is also performed through the index value, so changing the order will also undermine compatibility.
· Avoid using default function parameters
Setting the default value for function parameters is convenient for customers, but may compromise compatibility. The default value is given along with the header file. Changing the default value will cause compatibility problems.
The above is what I can think of. I hope it will help you.
View the source of this Article