What is the Richter replacement principle
The Richter substitution principle (Liskov substitution principle LSP) is defined as: where any base class can appear, subclasses must be present. LSP is the cornerstone of inheritance reuse, only if the derived class can replace the base class, the function of the Software unit is not affected, the base class can be truly reused, and the derived class can add new behavior on the base class. Why need the Richter replacement principle
The Richter replacement principle looks like nothing great, not the inheritance to pay attention to the loss of detail, young man, you think it is dangerous ah. In fact, the principle of the Richter replacement is often violated, as I illustrate below:
We have defined a rectangular class:
public class Rectangle {
private int width;
private int height;
public void setwidth (int width) {
this.width = width;
System.out.println ("Rectangle width" + width);
}
public void setheight (int height) {
this.height = height;
System.out.println ("Rectangle height" + height);
}
Mathematically, we think that a square is a special rectangle (equal in length and width), so if we need a square class, we'll usually write the code as follows:
public class Square extends rectangle{
}
Did it ever occur to you that a square needs only the edge length to fulfill its needs, but since Square inherits from Rectangle, the square class must have width and height, even though we make them change at the same time while setting them, but The width and height must have one that is superfluous. So if we need to draw tens of thousands of squares, we will produce thousands of extra width or height.
In addition, there is a strange problem with square inheriting Rectangle: Because of the principle of the Richter substitution, as long as the Rectangle class can appear, the square class must also appear, then any object to the Rectangle class SetWidth ()/ where the SetHeight () method operates, it should be possible to do the same with objects of the Square class. However, the Square class is clearly long and equal, why do the same operation two times.
If you think this example is not convincing enough, let me cite an example to illustrate that even if we rewrite the SetWidth ()/setheight () method, there is still a problem:
public class Square extends rectangle{
@Override public
void setheight (int height) {
super.setwidth (height );
Super.setheight (height);
System.out.println ("Square height" + height);
}
@Override public
void setwidth (int width) {
super.setwidth (width);
Super.setheight (width);
System.out.println ("Square width" + width);
}
Then add one such method to the class that operates Square and Rectangle:
public void Initrec (Rectangle r) {
r.setwidth (6);
R.setheight (ten);
}
Because of the principle of the Richter substitution, we can of course pass the square object to this method, so the question comes, which is the edges of the square class object. We'll pass Rectangle and Square into the method to see the actual output:
Rec
Rectangle Width6
Rectangle height10
Squ
Rectangle Width6
Rectangle HEIGHT6
Square Width6
Rectangle Width10
Rectangle height10
Square height10
You will also find that this time squ behavior has become very strange, its edges in the end is 6 or 10. Of course, it's easy to fix this Bug, but that doesn't mean the code is fine, because in order to fix the bug, we have to go back and modify the class to fit the actual situation, and then look at the following example:
It's normal for the rectangle to compute the area. So let's add a way to calculate the area for the Rectangle class:
public int Getrecarea (Rectangle r) {return
r.getheight () *r.getwidth ();
}
This method is then put into the Initrec () method, so when we pass the square object to the Initrec () method, there is certainly no problem, but the calculated area must be problematic, as we have just said that even the square object's edges are not sure, How are we going to determine the size of it? The problem is exactly where it is.
We may now find that even such a simple relationship between Square and Rectangle will make us miserable in the maintenance process, constantly go back and modify the code within the class, adding a variety of logic to circumvent the error. Many people will feel very strange, so write class should be no problem ah, why there is such a mistake ah.
In fact, the root of the problem is that, in programming, the square class cannot be considered a subclass of the Rectangle class, even though the square is a special rectangle in mathematics. Because the behavior and attributes of the Square class are inconsistent with the behavior and attributes of the Rectangle class, the behavior and properties of the two classes are abstracted, and we find that the two cannot agree at all:
Square attributes only the side length, while the Rectangle has the width and height
Square requires only one way to set the edge length, while Rectangle requires two set methods.
So from this example we can also find that, in the process of programming, the design of inheritance relationship between classes can not be carried out according to common sense, but need to start from the actual, from the abstract behavior of class, abstract attributes, consider whether the relationship between classes can become a is-a relationship, if subclass B and parent Class A can not achieve complete Is-a relationship, then we can not inherit. In other words, if some implementations in class B need to rely on some implementations of class A, then we should consider transferring this part of the implementation to the interface so that both class A and Class B implement the interface.