The Richter Substitution Principle
The Richter Substitution Principle (LiskovSubstitutionPrinciple, LSP) is one of the five principles of object-oriented design, which was proposed by computer scientist Barbara Liskov. The principle states that all references to objects of a parent class can be smoothly replaced with objects of its child class without program errors or exceptions. In other words, if a method of a class uses a parent class as an argument, then its subclasses should also be able to be passed into the method and should not have any effect on the behavior of the method. In addition, the subclass should also be able to extend or override the methods of the parent class without changing the methods of the parent class.
The main purpose of this principle is to ensure that classes are extensible and flexible while reducing code coupling. Failure to adhere to the LSP can result in bloated, lengthy code that is difficult to maintain and extend.
There are three important conditions for LSP:
1. Subclasses must fully implement the methods of the parent class. This means that the subclass cannot remove any of the parent’s methods or change their behavior.
2. Subclasses can have their own methods. Subclasses can have their own methods, but they cannot change the methods of the parent class.
3. Subclasses can have their own attributes. Subclasses can have their own attributes, but they must be the same or more specific than the parent class.
As an example, if we have an Animal class and a Dog class, the Dog class is a subclass of the Animal class.The Animal class has a makeSound() method, and the Dog class extends that method so that it can not only make animal sounds, but also wag its tail. In this case, the Dog class follows the LSP.
Another example is the Shape class and the Rectangle class.The Shape class is an abstract class that defines a method for calculating an area.The Rectangle class inherits from the Shape class and implements a method for calculating the area of a rectangle. In this case, the Rectangle class still follows the LSP because it extends the functionality of the Shape class without modifying the original behavior.
In short, LSP requires us to focus on code maintainability, extensibility, and reusability when designing classes to avoid duplicate code and unnecessary code coupling. Only by following the LSP principles can we better achieve the goals of object-oriented design and improve code quality and development efficiency.
What is the Richter Substitution Principle
Richter Substitution Principle (LiskovSubstitutionPrincipleLSP)One of the basic principles of object-oriented design. LSP is the cornerstone of inheritance reuse, the base class can be truly reused only if the derived class can replace the base class and the functionality of the software unit is not affected, and the derived class is able to add new behaviors based on the base class.
In this way, the question arises, “How do we go about measuring the quality of inheritance relationships?”
Liskov proposed a principle of inheritance in 1987 ” Inheritanceshouldensurethatanypropertyprovedaboutsupertypeobjectsalsoholdsforsubtypeobjects.”- – “Inheritanceshouldensurethatanypropertyprovedaboutsupertypeobjectsalsoholdsforsubtypeobjects.” That is, a subclass has an is-A relationship between them when an instance of the subclass should be able to replace any instance of its superclass.
This principle is called the LiskovSubstitutionPrinciple – the Richter Substitution Principle.
Example of Richter’s Substitution Principle
LSP (Richter’s Substitution Principle):
In principle, a subclass object is introduced to a parent object, which can be said to replace the parent class, and appears in place of the parent object wherever the parent class is able to appear
On the other hand, a parent object cannot be replaced by a subclass object, a property known as the Richter’s Substitution Principle.
1. Subclasses can be implicitly converted to parent classes
2. Parent classes must be strongly transitive
is:Equivalent to the judgment. AisB A is not B or A is not a subclass of B
as:Judgment before conversion. (It’s relatively safer than traditional forced conversions, which crash the program if the conversion fails. Then use as)
Bb: defines a reference variable b on the stack, which is a null reference and is stored on the stack to hold the address of future references
b=newB: creates an object of class B with the new keyword, which is stored on the managed heap, and the CRL also creates objects of the type of the object when it creates instances of it. also creates its type object, the object instance’s memory in the heap consists of, field, type, type object pointer, synchronization index block, type object pointer points to the type object
The type object’s memory in the heap consists of the type object pointer, index block, static field, list of methods
Aa=b:Declare a reference variable of type A reference variable a and point its actual address to the instance of that object pointed to by b
When a method is invoked, the type of that object a is checked directly by first finding the type object in the heap to see if in fact there is a method for that method
If so If it does, it is called directly. If it doesn’t, it continues to look up through the type object’s type object pointer until it finds the method
After it finds the method, it first checks to see if the method is virtual, and if it’s non-virtual it calls it directly, and if it’s virtual, i.e., if it’s a virtual method, i.e., if there’s a virtual modifier, then it will refer to the variable a, and look for an instance of the object’s class, B, and find out whether the method has been reimplemented. If there is a reimplementation of the virtual method, if there is . Execute, not continue to look up until you find
Since MethodG is a virtual method, you will find instance B, and since B rewrites MethodG, you will directly output .