What is the Li's replacement principle?
If for each type of T1 object O1, there is an object O2 of Type T2, so that all programs P defined by T1 are replaced by O2 when all objects O1, if the program P does not change, Type T2 is a subclass of Type T1. That is to say, if a software entity uses a base class, it must be applicable to its subclass.
Analogy:
public class A {}
public class B extends A {}
public class Tests { @Test public void tests() { A a = new A(); method(a); B b = new B(); method(b); } public void method(A a) { }}When B is a subclass of A, if there is a method (a A), then method (New B () must also be true.
The Li's replacement principle is the cornerstone of inheritance and utilization.
Here is a very famous example of whether a square is a subclass of a rectangle.
public class Rectangle { private long width; private long height; public long getWidth() { return width; } public void setWidth(long width) { this.width = width; } public long getHeight() { return height; } public void setHeight(long height) { this.height = height; }}When width and height are equal, a square is obtained, because some objects in a rectangle are square. Is this correct?
Let's look at the Square source code.
public class Square { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; }}The code above shows that a square is not a subclass of a rectangle.
In fact, a square cannot be a subclass of a rectangle. Why?
Assume that square is a subclass of rectange, as shown below:
public class Square extends Rectangle { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } @Override public long getHeight() { return getSide(); } @Override public long getWidth() { return getSide(); } @Override public void setHeight(long height) { setSide(height); } @Override public void setWidth(long width) { setSide(width); }}
As long as the width and height values are assigned values, the width and height are also copied. When a resize method is defined, this method increases the width until the length is exceeded, if a rectangle is passed in, this method is fine. If square is passed in, this method will cause overflow.
public class Tests { public void resize(Rectangle rectangle) { while (rectangle.getHeight() <= rectangle.getWidth()) { rectangle.setWidth(rectangle.getWidth() + 1); } }}
Therefore, a square cannot be a subclass of a rectangular shape.
Okay, we need to refactor the code. The square and the rectangle are all quadrilateral. We have invented an edge-adding class that converts the rectangle and the square into its specific subclass, in this way, the relationship between the rectangle and the square does not conform to the Li's replacement principle.
public interface QuadRange { public long getWidth(); public long getHeight();}
public class Rectangle implements QuadRange { private long width; private long height; public long getWidth() { return width; } public void setWidth(long width) { this.width = width; } public long getHeight() { return height; } public void setHeight(long height) { this.height = height; }}
public class Square implements QuadRange { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } @Override public long getWidth() { return getSide(); } @Override public long getHeight() { return getSide(); }
<Span style = "font-family: Arial, Helvetica, sans-serif;"> in this way, there is no value Assignment Method in the base class, therefore, the resize method cannot be suitable for base classes such as quadrange, but can only be suitable for different concrete subclass rectangle and square, so that the ryth replacement principle cannot be broken. </span>