TOP5. Richter's substitution principle-object-oriented design principle

         Definition of Richter's Substitution Principle

The role of the Richter substitution principle

How to implement the Richter substitution principle


Definition of Richter's Substitution Principle


The Liskov Substitution Principle (LSP) was an article published by Ms. Liskov of the MIT Computer Science Laboratory at the 1987 "Object-Oriented Technology Summit" (OOPSLA) "Data Abstraction and Hierarchy" (Data Abstraction and Hierarchy), she proposed: Inheritance should ensure that any property proved about supertype objects also holds for subtype objects ).

The Richter's Substitution Principle mainly elaborates some principles about inheritance, namely when inheritance should be used and when should not be used, and the principles behind it. The Richter replacement was originally the basis of inheritance and reuse. It reflected the relationship between the base class and the subclass, was a supplement to the principle of opening and closing, and a specification for the concrete steps to achieve abstraction.

The role of the Richter substitution principle


The main functions of the Richter substitution principle are as follows.

  1. The Richter substitution principle is one of the important ways to realize the opening and closing principle.
  2. It overcomes the shortcomings of poor reusability caused by overriding the parent class in inheritance.
  3. It is a guarantee of correctness of action. That is, the extension of the class will not introduce new errors to the existing system, reducing the possibility of code errors.

How to implement the Richter substitution principle


In general, the Richter substitution principle is: subclasses can extend the functions of the parent class, but cannot change the original functions of the parent class. That is to say: when the subclass inherits the parent class, in addition to adding new methods to complete the new functions, try not to override the methods of the parent class.

If the new function is completed by rewriting the parent class method, it is simple to write, but the reusability of the entire inheritance system will be relatively poor, especially when polymorphism is used frequently, the probability of program operation errors will be very large .

If the program violates the Richter substitution principle, the objects of the inherited class will run into errors where the base class appears. At this time, the correction method is: cancel the original inheritance relationship and redesign the relationship between them.

Regarding the example of the Richter substitution principle, the most famous one is "a square is not a rectangle". Of course, there are many similar examples in life. For example, penguins, ostriches, and kiwis are classified from a biological point of view. They belong to birds; but from the perspective of the inheritance relationship of classes, because they cannot inherit the "bird" can fly Functions, so they cannot be defined as subcategories of "birds". Similarly, because "balloon fish" can't swim, it cannot be defined as a subtype of "fish"; "toy cannon" cannot blow up enemies, so it cannot be defined as a subtype of "cannon".

Let's take "Kiwi is not a bird" as an example to illustrate the principle of Richter substitution.

[Example 2] The application of the Richter substitution principle in the example of "Kiwi is not a bird".

Analysis: Birds generally fly. For example, the speed of swallows is about 120 kilometers per hour. However, New Zealand kiwis are unable to fly due to degraded wings. If you want to design an example, calculate the time it takes for these two birds to fly 300 kilometers. Obviously, using the swallow to test this code, the result is correct, and the required time can be calculated; but using the kiwi bird to test, the result will be "division by zero exception" or "infinity", which obviously does not meet expectations. Its class diagram As shown in Figure 1.
 

Class diagram of "Kiwi is not a bird" example


                                                             Figure 1 Class diagram of the "Kiwi is not a bird" example


The program code is as follows:

package principle;

public class LSPtest {
    public static void main(String[] args) {
        Bird bird1=new Swallow();
        Bird bird2=new BrownKiwi();
        bird1.setSpeed(120);
        bird2.setSpeed(120);
        System.out.println("如果飞行300公里:");
        try {
            System.out.println("燕子将飞行"+bird1.getFlyTime(300)+"小时.");
            System.out.println("几维鸟将飞行"+bird2.getFlyTime(300)+"小时。");
        } catch(Exception err) {
            System.out.println("发生错误了!");
        }
    }
}
// 鸟类
class Bird {
    double flySpeed;
    public void setSpeed(double speed) {
        flySpeed=speed;
    }
    public double getFlyTime(double distance) {
        return(distance/flySpeed);
    }
}
// 燕子类
class Swallow extends Bird{}
//几维鸟类
class BrownKiwi extends Bird {
    public void setSpeed(double speed) {
           flySpeed=0;
    }
}

The results of the program are as follows:

如果飞行300公里:
燕子将飞行2.5小时.
几维鸟将飞行Infinity小时。
程序运行错误的原因是:几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。正确的做法是:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。其类图如图 2 所示。

Class diagram of the "Kiwi is an animal" example


                                                             Figure 2 Class diagram of the "Kiwi is an animal" example

<The principle of opening and closing                                                                                                                                                                    depends on the principle of inversion>

Guess you like

Origin blog.csdn.net/m0_38023584/article/details/106343952