Liskov Substitution Principle means that for every object o1 of type T1, there is an object O2 of type T2, so that all programs P defined as T1 behave the same when o1 is replaced with O2. Then type T2 is a subtype of type T1.

This definition seems a little bit abstract, but let’s think about it a little bit more. If a software entity applies to a parent class, then it must apply to its subclasses. All references to the parent class must be able to transparently use the objects of the subclass, which can replace the objects of the parent class without changing the program logic. A subclass may extend the functionality of its parent class, but it cannot change the functionality of its parent class.

(1) A subclass can implement abstract methods of the parent class, but cannot override non-abstract methods of the parent class.

(2) Subclasses can add their own unique methods.

(3) When a method of a subclass overrides a method of the parent class, its preconditions (i.e. the method’s input/input parameters) are looser than the input parameters of the parent class method.

(4) When a method of a subclass implements a method of the parent class (overriding/overloading or implementing an abstract method), the postcondition of the method (that is, the output/return value of the method) is stricter or the same as that of the parent class.

In the case of the open and close principle, I foiled the reefer substitution principle by overwriting the parent getPrice() method and adding getOriginPrice() to get the source code. Instead of overwriting the getPrice() method, add the getDiscountPrice() method:

public class JavaDiscountCourse extends JavaCourse {

    public JavaDiscountCourse(Integer id, String name, Double price) {

        super(id, name, price);

    }

    public Double getDiscountPrice(a){

        return super.getPrice() * 0.61; }}Copy the code

Using the Richter substitution principle has the following advantages:

(1) The overflow of constraint inheritance is an embodiment of the open-closed principle.

(2) To strengthen the robustness of the program, at the same time, it can also achieve very good compatibility when changing, improve the maintainability and expansibility of the program, and reduce the risk introduced when the demand changes.

Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class = Rectangle class

public class Rectangle {

    private long height;

    private long width;

    @Override

    public long getWidth(a) {

        return width;

    }

    @Override

    public long getLength(a) {

        return length;

    }

    public void setLength(long length) {

        this.length = length;

    }

    public void setWidth(long width) {

        this.width = width; }}Copy the code

Rectangle class = Square; Rectangle class = Square;

public class Square extends Rectangle {

    private long length;

    public long getLength(a) {

        return length;

    }

    public void setLength(long length) {

        this.length = length;

    }

    @Override

    public long getWidth(a) {

        return getLength();

    }

    @Override

    public long getHeight(a) {

        return getLength();

    }

    @Override

    public void setHeight(long height) {

        setLength(height);

    }

    @Override

    public void setWidth(long width) { setLength(width); }}Copy the code

Create the resize() method in our test class. The width of the rectangle should be greater than or equal to its height. Let the height increment until the height equals the width and it becomes a square:

public static void resize(Rectangle rectangle){

    while (rectangle.getWidth() >= rectangle.getHeight()){

        rectangle.setHeight(rectangle.getHeight() + 1);

        System.out.println("width:"+rectangle.getWidth() + ",height:"+rectangle.getHeight());

    }

    System.out.println("End of resize method" +

            "\nwidth:"+rectangle.getWidth() + ",height:"+rectangle.getHeight());

}
Copy the code

The test code is as follows:

public static void main(String[] args) {

    Rectangle rectangle = new Rectangle();

    rectangle.setWidth(20);

    rectangle.setHeight(10);

    resize(rectangle);

}
Copy the code

The running result is shown in the figure below.

We find that the height is larger than the width, which is a very normal situation in a rectangle. Now let’s replace the Rectangle class with its subclass Square and change the test code:

public static void main(String[] args) {

    Square square = new Square();

    square.setLength(10);

    resize(square);

}
Copy the code

The above code runs in an infinite loop, which violates the Richter’s substitution principle. After replacing the parent class with a subclass, the program runs without reaching the expected results. Therefore, our code design is risky. Richter’s substitution principle only exists between parent class and child class. Let’s create an abstract Quadrangle interface based on the common rectangle and square:

public interface Quadrangle {

    long getWidth(a);

    long getHeight(a);

}
Copy the code

Change Rectangle class Rectangle class:

public class Rectangle implements Quadrangle {

    private long height;

    private long width;

    @Override

    public long getWidth(a) {

        return width;

    }

    public long getHeight(a) {

        return height;

    }

    public void setHeight(long height) {

        this.height = height;

    }

    public void setWidth(long width) {

        this.width = width; }}Copy the code

Modify Square class Square:

public class Square implements Quadrangle {

    private long length;

    public long getLength(a) {

        return length;

    }

    public void setLength(long length) {

        this.length = length;

    }

    @Override

    public long getWidth(a) {

        return length;

    }

    @Override

    public long getHeight(a) {

        returnlength; }}Copy the code

At this point, if we change the parameter of the resize() method to the Quadrangle interface, an error will be reported inside the method. The Square class has no setWidth() and setHeight() methods. Therefore, to prevent inheritance overload, the arguments to the resize() method can only be Rectangle classes. Of course, we’ll cover this in more detail later in the design patterns section.

This article is “Tom play structure” original, reproduced please indicate the source. Technology is to share, I share my happiness! If this article is helpful to you, welcome to follow and like; If you have any suggestions can also leave a comment or private letter, your support is my motivation to adhere to the creation. Pay attention to “Tom bomb architecture” for more technical dry goods!

Other Design Principles

Open-closed Principle (OCP)

Dependence Inversion Principle (DIP)

Simple Responsibility Pinciple (SRP)

Interface Segregation Principle (ISP)

Law of Demeter LoD

Composite/Aggregate Reuse Principle, CARP