Change your Mind
Once in school data structure course, the first class, the teacher told us: program = data structure + algorithm. This sentence to my later study data structure played a great role in the positive role.
But then I learned the C + + object-oriented part, which makes me in some places can not make sense. After thinking for a long time, I came to another conclusion, in object-oriented programs, program = object & behavior. I use & here to illustrate that objects are related to behavior. Behavior is the behavior of an object, and the object is responsible for its own behavior.
This shift in thinking is very important in the process from PO to Oo, let me give you an example:
If we use PO's thinking, we want to achieve "rabbit walk" and "People walk", what will we do?
First, write a "rabbit" structure. struct rabbit{}r;
Then there is a "rabbit walk" algorithm. void rabbitWalk(rabbit r);
Finally, the "rabbit" Using the "Bunny Walk" algorithm. rabbitWalk(r);
"People walk" and "Rabbit Walk" similar to:
struct human{}h;void humanWalk(human h);humanWalk(h);
This is the thinking of data structure + algorithm. Program "Rabbit Walk" = Data Structure "Rabbit" + Algorithm "Rabbit Walk". Program "Human Walk" = Data Structure "human" + algorithm "human Walk".
What if the data structure "human" + algorithm "Rabbit Walk"?
First create a "Rabbit" Object class rabbit{};rabbit r;
Because rabbits need to "walk," This behavior class rabbit{ void walk(){}};
is added to the class
Let the "Rabbit" object perform its "Walk" behavior. r.walk();
Similarly, the "Human Walk" program can be implemented as follows:
public animal{void walk(){}};human h;h.walk();
Here, it is the object that invokes its own behavior. Two "walking" behaviors are irrelevant, although they have the same name. It is up to the object to decide which "walk" behavior they invoke, and what programmers have to do is simply let the object perform their "walk" behavior. People do not walk with rabbits, so the way to walk with rabbits is impossible.
Object oriented
Here's a simple example of a change in thinking from Po to Oo, and here's some of the specific features that OO has to say about the PO. The explanation of the relevant terms can be found on the internet and will not be expanded in detail here.
Objects and classes
An object is an instance of a real-world relationship, and a class is an abstraction of an object. Note that in object-oriented, there are usually first-class objects. The first is that we need an object, we can abstract it into a class, enrich its behavior. Then use this class to instantiate an object to use.
A class is not necessarily a name, it can also be a verb.
For example, a "pleasant goat" is an object, the abstract sheep is a class.
Pleasant Goat "from school to the village head of the home" can also be an object, abstract walk this class.
Message delivery and dynamic distribution
Take a look at two lines of code
xiyangyang.walk(hua_ban);xiyangyang.walk(bike);
Message passing means that when the program wants to use a skateboard to walk, it uses this statement to send a walk message to Xiyangyang with Hua_ban parameters.
So what's the news going to do with it? We don't need to worry about this, because it's up to Xiyangyang. This is dynamic distribution.
Packaging
PO also has the concept of encapsulation, but Oo does better.
Combination and inheritance
Perhaps we are more familiar with the succession, the combination is unfamiliar. Here they are compared, to show that they can achieve similar effects, but the purpose is different.
When we want to add behavior to a class, we usually think of inheritance. But I, as a primary function of inheritance, is to provide a unified interface, and it is recommended to use a combination in terms of functional expansion.
For example, there was a class called "sheep". But now we need a "talking sheep" object, how to do it?
It's easy to think of a solution:
This is an example of inheritance, as the sheep evolved a new breed of speak behavior.
In fact, it also has a way of implementation, that is, the use of combination:
If inheritance is likened to evolution, then the combination can be interpreted as such: it can be explained. The sheep still doesn't speak, but it gets a sounder that uses the speak behavior of the sounder to speak for the sheep.
Polymorphic
Polymorphism is the most abstract and difficult to explain concept here, so here's a story to illustrate:
In the big forest to hold the running race, the small animals all come to register.
Elephant: I'm an elephant, I'll sign up. Administrator: OK, please take the elephant to run the way to participate in the competition.
Rhino: I'm a rhino, I'll sign up. Admin: Rhino? It's supposed to be a cow, right? Please take the bull to run the game.
Small ox: I am Xiao Huang, I come to register. admin: What is Xiao Huang? You can't run a running race without a "little yellow run".
The end: The Elephant finished the game. The rhino is back in the middle because the bull's running style doesn't fit it. Little Ox did not enter the competition.
admin: I don't care what kind of animal you are or how you run. As long as you have a run, you can play and run in your own way.
The result: Everyone took part in the game and finished the game in their own way.
C++
C + + has done a lot of functional extension on the foundation, but the subject of this article is object-oriented, and other aspects are not explained. As an object-oriented language, C + + is bound to support the object-oriented features mentioned above. The following examples demonstrate:
Objects and classes
Class animal{stringName Public:Animal(stringN):name(n) {}voidIntroduce () {cout<<"My name is"<<name;}voidWalk () {cout<<"Default Walk"<<endl;}}; Class Sheep: Publicanimal{ Public:Sheep(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"Walk Like a sheep"<<endl;}}; Class Human: Publicanimal{ Public:Human(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"Walk Like a human"<<endl;}};voidTest () {Sheep A ("Xiyangyang"); Human B ("Xiaohuangren"); A.walk (); B.walk ();}
Run results
mynameis xiyangyangwalk like a sheepmynameis xiaohuangrenwalk like a human
In this example: animal, sheep, human are classes, but both A and B objects.
Inherited
Class animal{stringName Public:Animal(stringN):name(n) {}voidIntroduce () {cout<<"My name is"<<name;}voidWalk () {cout<<"Default Walk"<<endl;}}; Class Sheep: Publicanimal{ Public:Sheep(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a sheep"<<endl;}voidSpeak () {introduce ();cout<<"Sorry, I can ' t speak"<<endl;}}; Class De_dao_gao_yang: Publicsheep{ Public:De_dao_gao_yang(stringN):Sheep(n) {}voidSpeak () {introduce ();cout<<"I ' M de Dao Gao Yang, I can speak"<<endl;}};voidTest () {De_dao_gao_yang A ("Yang da Xian"); A.speak (); A.walk (); Sheep B ("Normal sheep"); B.speak (); B.walk ();}
Operation Result:
mynameis yang da xianI‘m de dao gao yang, I can speakmynameis yang da xianI walk like a sheepmynameis normal sheepsorry, I can‘t speakmynameis normal sheepI walk like a sheep
In this example, a sheep through the inheritance to achieve the speech function, B sheep is an ordinary sheep, no speech function. But A and B are the same way of walking.
Combination
classspeaker{ Public:voidSay_a_word (stringWord) {cout<<word<<endl; }};classanimal{stringName Public: Animal (stringN): Name (n) {}voidIntroduce () {cout<<"My name is"<<name;}voidWalk () {cout<<"Default Walk"<<endl;}};classSheep: Publicanimal{speaker *hu_die_jie_fa_sheng_qi; Public: Sheep (stringNBOOLCan_speak =false): Animal (N), Hu_die_jie_fa_sheng_qi (NULL) {if(Can_speak = =true) Hu_die_jie_fa_sheng_qi =NewSpeaker (); } ~sheep () {if(Hu_die_jie_fa_sheng_qi! = NULL)DeleteHu_die_jie_fa_sheng_qi; Hu_die_jie_fa_sheng_qi = NULL; }voidWalk () {introduce ();cout<<"I Walk Like a sheep"<<endl;}voidSpeak () {introduce ();if(Hu_die_jie_fa_sheng_qi = = NULL)cout<<"Sorry, I can ' t speak"<<endl;ElseHu_die_jie_fa_sheng_qi->say_a_word ("This is a speaker, hello"); }};voidTest () {Sheep A ("Xiyangyang",true), B ("Nuanyangyang"); A.speak (); A.walk (); B.speak (); B.walk ();}
Run results
mynameisis a speaker, hellomynameis xiyangyangI walk like a sheepmynameis nuanyangyangsorry, I can‘t speakmynameis nuanyangyangI walk like a sheep
In this example, a sheep through the combination to achieve the speech function, B sheep is a common sheep, no speech function. But A and B are the same way of walking.
Polymorphic
Class animal{stringName Public:Animal(stringN):name(n) {}voidIntroduce () {cout<<"My name is"<<name;}Virtual voidWalk () {cout<<"Default Walk"<<endl;}}; Class Sheep: Publicanimal{ Public:Sheep(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a sheep"<<endl;}}; Class Human: Publicanimal{ Public:Human(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a human"<<endl;}}; Class Monkey: Publicanimal{ Public:Monkey(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a monkey"<<endl;}}; Class Duck: Publicanimal{ Public:Duck(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a duck"<<endl;}}; Class Pig: Publicanimal{ Public:Pig(stringN):Animal(n) {}voidWalk () {introduce ();cout<<"I Walk Like a pig"<<endl;}};voidTest () {Animal * runner[5]; runner[0] =NewSheep"Xi Yang Yang"); runner[1] =NewHuman"Tai Shan"); runner[2] =NewMonkey"Kong Kong"); runner[3] =NewDuck"Tang Lao Ya"); runner[4] =NewSheep"Zhu Ba Jie"); for(inti =0; I <5; i++) Runner[i]->walk (); for(inti =0; I <5; i++) Delete runner[i];}
Operation Result:
mynameis xi yang yangI walk like a sheepmynameis tai shanI walk like a humanmynameis kong kongI walk like a monkeymynameis tang lao yaI walk like a duckmynameis zhu ba jieI walk like a sheep
In this case, runner is just a pointer to a animal type and does not know what animal it is actually pointing to (only when the instantiation is started to know that it is not known when it is used), but it will still invoke the corresponding behavior of the specific animal class.
Object-Oriented design principles
Clean code's Uncle Bob proposes five principles for object-oriented design, called solid. But in my opinion, the most important principle of OO design is to analyze the changes that may occur and how to respond to them.
Srp-single Responsibility principle (single duty)
A single principle of responsibility is a class that causes it to change for only one reason.
First look at such a class, does it conform to the principle of single responsibility?
As mentioned above, a very important premise in evaluating the reasonableness of an OO design is to speculate about change. is in the analysis of the design of the corresponding requirements, which places are very likely to change. The evaluation without this premise is one-sided and arbitrary.
In this case, we assume that for this sheep class, it supports which behaviors are prone to change, and the way in which it is called is also prone to change, so there are two reasons for this class to be modified and therefore not consistent with the principle of single responsibility.
How can we modify this design? A very common approach is to package changes. Here we encapsulate the "call" behavior, encapsulating it into another class speaker. Thus, when the way of sounding changes, only the speaker class needs to be modified.
Ocp-open-closed Principle (Open closed)
The open-close principle refers to the opening of extensions and the closure of modifications. In other words, it may sound strange to try to extend the functionality of the class by not modifying the code, but it can be done if it is well designed. For example, in the previous example, the method of sounding is extracted, then the method of sound can be expanded without the need to change the sheep class.
In this case, our needs have changed. We want this goat to make an MOU, while others (such as the frequency and monotony of the sound) remain the same. We soon figured out the solution
Lsp-liskov Substitution Principle (li shi substitution)
The substitution of a li means that in any place where the base class can be used, a derived class can be used instead of it. This seems to be taken for granted, since the derived class inherits the base class, then the base class has a behavior derived class of course, what can be said? However, referring to the example above, although derived classes inherit all the behavior of the base class, they do not say that the inherited behavior is meaningful to the derived class. For example, this high-level sounder, in fact, it does not support Mie This behavior, therefore does not meet the Li's substitution. How to improve it? Consider this scenario:
In fact, the substitution of Li, can be understood as the base class for derived classes, there is no redundant interface. We place the Mie and the MOU in parallel, and inherit speaker at the same time, and the parent class simply provides the interface, and the subclass implements the behavior.
As you can see from this example, inheritance and composition are similar but different in usage. Inheritance is typically used in order to unify the interface, while the combination is available for extended functionality.
Isp-interface segregation Principle (interface isolation)
Interface Isolation: A client-specific fine-grained interface is used.
When defining an interface, do we define a large interface or define multiple small interfaces? Here, we recommend the latter.
Multiple small interfaces may cause multiple interfaces to be difficult to manage, but the benefits are far greater than their drawbacks.
When an interface is large and requires many parameters, it is often used to accommodate a variety of situations. Some use cases use only these parameters, and some use only those ones.
If an interface has parameter a,b,c,d,e,f,g. But an application scenario actually only uses the a,b,c. Then when the parameter d of the interface is changed, it is actually not related to the use case. But it is not reasonable for a use case to change the way it is called because of this situation.
Did not think of a suitable example.
Dip-dependency inversion Principle (dependency inversion)
Dependency inversion means that we rely on abstraction rather than concrete implementation. Because Oo's greatest feature is its good at responding to change. As we said above, we want to encapsulate the changes. So what is more likely to change in an abstract and concrete implementation? is of course concrete implementation.
In the above example, speaker is abstract, Mie and MoU are implemented. Sheep now relies on speaker, so no matter whether we use the Mie sounder or the MoU sounding method, it has no effect on sheep, so it conforms to the dependency inversion principle.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
From procedure-oriented to object-oriented