Combination or inheritance is a problem
-- When we talk about object-oriented principles in a mode, we often have this problem when we use a combination of multiple features and inherit less people who just came into contact with the mode or learning mode. Why is the mode successful? Many people will say that the model is the accumulation of experience, and of course it is correct. But why does experience prove that this model is correct? This serves as the basic principle of object-oriented. It is precisely because the patterns are more or less in line with the basic principles of object-oriented, so pattern becomes an unbeaten rule in our object-oriented design and coding process. So what is the basic principle of object-oriented? This is the question we will discuss one by one. Simply speaking about the principles one by one is a few simple words, but it is very abstract and hard to understand. What should I do? Any theory, as long as there are vivid examples to explain or prove, can greatly help to understand. Therefore, we are going to explain the basic principles of object orientation from vivid examples. What are the examples? As we have mentioned above, the pattern follows these Principles greatly. So we take the pattern as an example to illustrate these principles. Aren't we confident in it? Now let's talk about one of the principles: to extend the functions of a class, we need to combine more and use less inheritance. For Class extension, in the object-oriented programming process, we first think of class inheritance, which inherits the parent class from the Child class, thus completing the extension of the Child class function. However, the object-oriented principle tells us that the extension of class functions should be combined with less inheritance. The reasons are as follows: 1. the inheritance of sub-classes to the parent class is all public and protected inheritance, this allows the subclass to inherit methods that are useless or even harmful to the subclass. In other words, the subclass only wants to inherit a part of the method of the parent class. What should I do? Second, the actual objects are ever-changing. If each class of objects has its own class, even though these classes inherit their parent class, but sometimes it will still cause infinite expansion of the class. Third, the inherited subclass actually needs to be determined during the compilation period, which does not meet the condition that the object can be determined only during running. However, a combination can be much more flexible than inheritance, and an object can be determined at runtime. Hi! What is the use of so many things? We just want to see if the actual situation is like what we mentioned above? Let's take a look at the actual example! Now we need such a hashmap, except that it can be set as normal map values, such as get (Object OBJ ). It can also take values by bit, as in arraylist, in the order of the stored object pairs. For such a problem, we first think of a class that inherits the hashmap class and then uses an arraylist attribute to store the saved key. We take the value based on the key location, the Code is as follows: public class listmap extends hashmap {private list; Public listmap () {super (); this. list = new arraylist ();} public object put (Object key, object Value) {If (list. contains (key) {list. remove (key);} This. list. add (key); return Super. put (Key, value);} public object getkey (int I) {return this. list. get (I);} public object getv Alue (int I) {return this. get (getkey (I);} public int size () {return this. list. size () ;}} the listmap class extends hashmap to a certain extent, so it is easy to implement the functions we require above. Then we will test the class: listmap map = new listmap (); map. put ("A", "111"); map. put ("V", "190"); map. put ("ds", "132"); For (INT I = 0; I <map. size (); I ++) {system. out. println (map. getvalue (I);} the test result is: 111190132 is what we need to see. So, can this listmap class be safely used? If you have implemented this function, your colleagues or friends may use this class. The code below may be written: listmap map = new listmap (); map. put ("A", "111"); map. put ("V", "190"); map. put ("D", "132"); string [] list = (string []) map. values (). toarray (New String [0]); For (INT I = 0; I <list. length; I ++) {system. out. println (list [I]);} The result is as follows: 132111190. Why? The order is not correct. Your friend came to you and said that the code you wrote was wrong? You are surprised to tell me the code. So you can see the above Code. You swear, asshole. Why didn't you use my getvalue method? Isn't the values method the same as your friend's comment header? Didn't you tell me you couldn't use it? Through the above example, we can see the first danger of inheritance: inheritance inherits all the public and protected methods of the parent class without authorization. If your subclass does not overwrite some methods, it will cause harm to your subclass. In the listmap class above, you did not overwrite the values method inherited from the hashmap class, and this method is still based on the hashmap method, Without sequential values. At this time, if we use the value obtained by this method in the listmap class object, we will not implement the above requirements. In the following example, you have heard a friend's complaint and shook your head. You can't blame him if you think about it. You have to rewrite the values method in the listmap class, and then muttered, should I overwrite all the public methods of the hashmap class in the listmap class? There is no need to use many methods at all ?...... By the way, many methods do not need to be used in listmap, but you have to rewrite them in listmap if you use inheritance. If a combination is used, the above troubles will be eliminated: public class mylistmap {private hashmap map; private list; Public mylistmap () {This. map = new hashmap (); this. list = new arraylist ();} public object put (Object key, object Value) {If (list. contains (key) {list. remove (key);} This. list. add (key); return this. map. put (Key, value);} public object getkey (int I) {return this. list. get (I);} public object getvalue (int I) {return this. map. get (Getkey (I) ;}public int size () {return this. List. Size () ;}} in this way, your friends can only use your getkey and getvalue methods. If he complained to you that there is no values method, you can do your best to satisfy his requirements and add the method to him, without worrying that there may be methods that have not been overwritten. Let's look at the adapter mode. The purpose of this mode is very simple: I have implemented some whatihave interfaces, but I think these functions are not enough, I also need to take some functions from the Resource class for my use. The solution to the adapter mode is as follows: public interface whatihave {public void g ();} public class resource {public void F (){......} Public void H (){......} The above are two basic classes. Obviously, the class we want must have both the G () method and the F () and H () methods. Public class whatiwant implements whatihave {private resource res; Public whatiwant () {res = new resource ();} public void g (){......} Public void F () {This. res. F ();} public void H () {This. res. H () ;}} above is a simple solution to the problem in the adapter mode. We mainly use combination instead of inheritance for the resource class. There are multiple reasons for this: first, Java does not support multiple inheritance. If you need to use several different resource classes, inheritance will not solve the problem. Second, if there is another method for the resource class: K (), if we cannot use it in the whatiwant class, inheritance will cause extra method problems. If the adapter mode has a very simple and clear purpose for the application of the combination, then the decorator mode is simply amazing for the application of the combination. Let's start with the best example of the decorator model. Coffee shops need to sell all kinds of coffee: black coffee, sugar, ice, milk, chocolate, etc. A customer wants to buy coffee. He can buy any one or more coffee products. As soon as this question is raised, we are most likely to think of inheritance. For example, coffee with sugar is a kind of coffee that meets the expression of ia a. Obviously, coffee with sugar is a subclass of coffee. So we can immediately assign action. For coffee, we make coffee, coffee with sugar: sugarcoffee, coffee with ice: icecoffee, coffee with milk: milkcoffee, coffee with chocolate: chocolatecoffee, coffee with sugar and ice: sugaricecoffee ...... Alas, we found the problem: in this case, we have a lot of classes. But the boss of the coffee shop has not let us go, and he forced us to add steam coffee and pressurized coffee. As a result, we found that every new type is added, our classes seem to increase in geometric series, and we are all going crazy. This example shows us the second disadvantage of inheritance, which will make our subclass quickly expand to an astonishing number. What should I do? Our decorator mode finds a combination to solve the problem for us. Next let's take a look at how the decorator mode solves this problem. The first is their common interface: public interface product {public double money ();} Coffee class: public class coffee implements product {public double money () {return 12 ;}} with sugar: public class sugar implements product {private product; Public sugar (product) {This. product = product;} public double money () {return product. money + 2 ;}} plus ice: public class ICE implements product {private product; Public ice (product produc T) {This. product = product;} public double money () {return product. money + 1.5 ;}} milk addition: public class milk implements product {private product; public milk (product) {This. product = product;} public double money () {return product. money + 4.0 ;}} plus chocolate: public class chocolate implements product {private product; Public chocolate (product) {This. product = product;} public double mon Ey () {return product. Money + 5.5;} Let's look at the client call. If the customer wants black coffee, the following is called: Product prod = new coffee (); system. out. println (prod. money (); If the customer needs iced coffee, the call is as follows: Product prod = new ice (new coffee (); system. out. println (prod. money (); If the customer wants to add sugar, ice, milk, and chocolate coffee, call the following: Product prod = new chocolate (New Milk (new ice (new sugar (); system. out. println (prod. money (); Through the above example, we can see another excellent advantage of the combination: the ability to create new objects at runtime. For example, in our iced coffee above, we don't have this class, but we can create this object by combining them at runtime, which greatly increases the flexibility of our program. If the coffee shop owner asks you to add a pressurized coffee, you will not worry about it any more, but add a class to it to solve all the problems. Trackback: http://tb.blog.csdn.net/TrackBack.aspx? Postid = 583558