2.0 - Design Patterns seven principles of software architecture design - Richter substitution principle

Richter substitution principle (Liskov Substitution Principle, LSP) means that if the object type for each of T1 o1, o2 are an object of type T2 and T1 so that all programs defined in P are replaced in all objects o1 o2 , the behavior of the program P has not changed, then the type is a subtype of type T2 T1. Definitions seem quite abstract, we have a new understanding of what can be understood as a software entity, if applicable, a parent, then it must apply to their sub-categories, all references to the parent class where the object must be able to transparently use its subclasses , subclass object can be replaced with the parent object, and change the program logic. According to this understanding, we summarize:

Extended meaning: subclass can extend the functionality of the parent class, but can not change the parent class of the original function. 1, sub-class parent class can implement the abstract methods, but non-abstract parent class can not be covered. 2, subclasses can add their own unique way. 3, when the parent class subclass overloads precondition method (i.e., a method for inputting / parameters into) the input parameters than the parent class method more relaxed. 4, when the method of the parent class implementation subclass (rewriting / or implement the abstract method overload), post-conditions of the process (i.e., process output / return value) than or equal to the parent more stringent.

 

Speaking in front of opening and closing the principles laid a hint when we remember that at the time of acquiring the discounted rewrite covered getPrice parent class () method adds a method to obtain the source code of getOriginPrice (), apparently violates the Richter Substitution principle. We modify the code, should not be covered getPrice () method, increased getDiscountPrice () method:

public class JavaDiscountCourse extends JavaCourse {
    public JavaDiscountCourse(Integer id, String name, Double price) {
   		 super(id, name, price);
    }
    public Double getDiscountPrice(){
   		 return super.getPrice() * 0.61;
    }
}

 Use Richter substitution principle has the following advantages: 1, constraints inherited flooding, a reflection of the principle of opening and closing. 2, to enhance the robustness of the program, you can do a very good compatibility while at the same time change, improve maintainability, scalability of the program. Reduce the risks introduced when requirements change. Now to describe a classic business scenario, with a square, rectangle and quadrilateral relationship explanation Richter substitution principle, we all know that a square is a special rectangle, then you can create a rectangle parent Rectangle class:

/**
 * @author madongyu
 * @projectName design-pattern-ma
 * @description: TODO
 * @date 2019/6/1817:28
 */
public class Rectangle {
    private long height;
    private long width;

    public long getHeight() {
        return height;
    }

    public void setHeight(long height) {
        this.height = height;
    }

    public long getWidth() {
        return width;
    }

    public void setWidth(long width) {
        this.width = width;
    }
}

Create a class that inherits rectangular square Square:

/**
 * @author madongyu
 * @projectName design-pattern-ma
 * @description: TODO
 * @date 2019/6/1817:28
 */
public class Square  extends Rectangle{
    private long length;

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    @Override
    public long getHeight() {
        return getLength();
    }

    @Override
    public void setHeight(long height) {
        setLength(height);
    }

    @Override
    public long getWidth() {
        return getLength();
    }

    @Override
    public void setWidth(long width) {
        setLength(width);
    }
}
/**
 * @author madongyu
 * @projectName design-pattern-ma
 * @description: TODO
 * @date 2019/6/1817:31
 */
public class Test {
    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("resize 方法结束" +
                "\nwidth:"+rectangle.getWidth() + ",height:"+rectangle.getHeight());
    }


    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(20);
        rectangle.setHeight(10);
        resize(rectangle);
    }
}

When larger than the width, in the rectangle is a very normal situation. Now we look at the following code, which replaced the rectangular Rectangle Square Square subclass, modify the test code:

public static void main(String[] args) {
        Square square = new Square();
        square.setLength(10);
        resize(square);
    }

This time when we run the cycle of death appeared, contrary to the Richter substitution principle, to replace the parent class is a subclass, the result of the program did not meet expectations. Therefore, our code design are certain risks. Richter substitution principle exists only between parent and child classes, inheritance constraints flooding. We come together to create a rectangle with square abstract quadrilateral Quadrangle interface is based on:

public interface Quadrangle {
    long getWidth();
    long getHeight();
}

Modify class Rectangle rectangle:

public class Rectangle implements Quadrangle {
private long height;
private long width;
@Override
public long getWidth() {
return width;
}
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public void setWidth(long width) {
this.width = width;
}
}

Modify square class Square categories:

public class Square implements Quadrangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getWidth() {
return length;
}
@Override
public long getHeight() {
return length;
}
}

At this time, if we put a resize parameter () method of the class into a quadrangle Quadrangle, internal method will be given. Because the square Square has no setWidth () and setHeight () method has. Accordingly, in order to restrict the proliferation of inheritance, a resize () method parameters can only Rectangle rectangle.

 

Guess you like

Origin blog.csdn.net/madongyu1259892936/article/details/93631675