This article mainly introduces the relevant information of Richter's substitution principle in detail, which has certain reference value. Interested friends can refer to it
Let's talk about Richter's substitution principle .
Definition 1: If for every object o1 of type T1, there is an object o2 of type T2, so that all programs P defined with T1 are represented in all objects o1 When changing to o2, the behavior of program P does not change, then type T2 is a subtype of type T1.
Definition 2: All places that reference a base class must be able to transparently use objects of its subclasses.
Origin of the problem: There is a function P1, which is completed by class A. Now it is necessary to expand the function P1, and the expanded function is P, where P consists of the original function P1 and the new function P2. The new function P is implemented by subcategory B of category A. Subcategory B may cause the original function P1 to malfunction while completing the new function P2.
Solution: When using inheritance, follow the Liskov substitution principle. When class B inherits class A, except for adding new methods to complete the new function P2, try not to override the methods of parent class A, and try not to overload the methods of parent class A.
Inheritance contains the following meaning: all methods that have been implemented in the parent class (relative to abstract methods) are actually setting a series of specifications and contracts, although it does not It is mandatory for all subclasses to comply with these contracts, but if subclasses arbitrarily modify these non-abstract methods, it will cause damage to the entire inheritance system. The Liskov substitution principle expresses this meaning.
As one of the three major features of object-oriented, inheritance brings great convenience to programming, but it also brings disadvantages. For example, using inheritance will bring intrusion to the program, reduce the portability of the program, and increase the coupling between objects. If a class is inherited by other classes, when this class needs to be modified, all subclasses must be taken into account. class, and after the parent class is modified, all functions involving the subclass may malfunction.
To give an example of the risk of inheritance, we need to complete a function of subtracting two numbers, and class A is responsible for it.
class A{ public int func1(int a, int b){ return a-b; } } public class Client{ public static void main(String[] args){ A a = new A(); System.out.println("100-50="+a.func1(100, 50)); System.out.println("100-80="+a.func1(100, 80)); } }
Running results:
100-50=50
100-80=20
Later, we need to add a new function: complete the addition of two numbers, and then sum it with 100. Class B is responsible for this. That is, Class B needs to complete two functions:
Subtract two numbers.
Add the two numbers, and then add 100.
Since class A has already implemented the first function, after class B inherits class A, it only needs to complete the second function. The code is as follows:
class B extends A{ public int func1(int a, int b){ return a+b; } public int func2(int a, int b){ return func1(a,b)+100; } } public class Client{ public static void main(String[] args){ B b = new B(); System.out.println("100-50="+b.func1(100, 50)); System.out.println("100-80="+b.func1(100, 80)); System.out.println("100+20+100="+b.func2(100, 20)); } }
After Class B is completed, the running result is:
100-50=150
100-80= 180
100+20+100=220
We found that an error occurred in the subtraction function that was originally running normally. The reason is that class B inadvertently rewrites the method of the parent class when naming the method, causing all the codes that run the subtraction function to call the rewritten method of class B, causing errors in the functions that originally ran normally. In this example, after referencing the function completed by base class A and replacing it with subclass B, an exception occurred. In actual programming, we often complete new functions by rewriting the parent class method. Although it is simple to write, the reusability of the entire inheritance system will be relatively poor, especially when polymorphism is used frequently, the program The chance of running errors is very high. If you have to rewrite the method of the parent class, a more common approach is: the original parent class and subclass both inherit a more popular base class, remove the original inheritance relationship, and use dependency, aggregation, combination and other relationships instead.
# Li's replacement principle is popular: Sub -class can expand the function of the parent class, but it cannot change the original function of the parent class. It contains the following 4 levels of meaning:
Subclasses can implement abstract methods of the parent class, but cannot override non-abstract methods of the parent class.
Subclasses can add their own unique methods.
When a method of a subclass overrides a method of a parent class, the preconditions of the method (that is, the formal parameters of the method) are looser than the input parameters of the parent class method.
When a method of a subclass implements an abstract method of the parent class, the postconditions of the method (ie, the return value of the method) are more stringent than those of the parent class.
It seems incredible, because we will find that we often violate the Liskov substitution principle in our own programming, but the program still runs well. So everyone will have this question, what will be the consequences if I insist on not following the Liskov substitution principle?
The consequence is: The chance of problems with the code you write will be greatly increased.
The above is the detailed content of Introduction to Richter Substitution Principle in Java. For more information, please follow other related articles on the PHP Chinese website!