The purpose of introducing the Richter substitution principle (liskovsubstitution principle,lsp) is to solve the strong coupling between parent and child classes in succession.
2.1 Love and hate entanglement of father-son relationship inheritance
In object-oriented languages, inheritance is an essential and excellent language mechanism.
Advantages of inheritance
Code sharing reduces the effort to create classes, each of which has methods and properties of the parent class;
Improve the reusability of code;
Subclasses can resemble the parent class, but also different from the parent class, "Dragon Born Dragon, chicken born chicken, the mouse is born to play the hole" is said that the son has the father's "species", "There are no two identical leaves in the world" is the difference between the child and the Father;
Improve the extensibility of the Code, the implementation of the method of the parent class can "do whatever", you do not see a lot of open source framework of the extension interface is through the inheritance of the parent class to complete;
Improve the openness of products or projects.
Disadvantages of inheritance
Inheritance is intrusive. As long as inheritance, you must have all the properties and methods of the parent class;
Reduce the flexibility of your code. Subclasses must have the properties and methods of the parent class, allowing the subclass to have more constraints in the free world;
Enhanced coupling. When the constants, variables, and methods of the parent class are modified, it is necessary to consider the modification of the subclass, and in the absence of a canonical environment, this modification can result in very bad results-large pieces of code need to be refactored.
Java uses the extends keyword to implement inheritance, which takes a single inheritance rule, C + + uses multiple inheritance rules, a subclass can inherit multiple parent classes.
From the overall point of view, the advantages outweigh the disadvantages, how can the "benefits" factor play the biggest role, while reducing the "harm" caused by the trouble?
The solution is to introduce the Richter replacement principle (Liskovsubstitution PRINCIPLE,LSP).
The principle of the Richter replacement
Richter Replacement principle (Liskov Substitution Principle,LSP)
- The first type of definition:
Although more authentic, but more obscure, understand can
- The second definition:
all references to base classes must be able to use the objects of their subclasses transparently.
Explanation: ""
as long as the parent class can appear where subclasses can appear, and the substitution of subclasses will not produce any errors or exceptions, the consumer may not need to know whether it is a parent class or a subclass at all.
However, the reverse is not possible, where there are subclasses, the parent may not be able to adapt.
2.2 Disputes constantly, rules suppressed
The Richter substitution principle defines a specification for good inheritance , and a simple definition contains 4 layers of meaning.
1. Subclasses must fully implement the method of the parent class
When we do the system design, we often define an interface or abstract class, and then encode the implementation, call the class directly into the interface or abstract class, in fact, here has used the Richter replacement principle.
- Abstract guns
- Public Abstract class Abstractgun {
- Public Abstract void shoot ();
- }
- Public class Handgun extends abstractgun {
- @Override
- Public void shoot () {
- System.out.println (" pistol shot: pa pa");
- }
- }
- Public class Rifle extends abstractgun {
- @Override
- Public void shoot () {
- SYSTEM.OUT.PRINTLN (" rifle shot: ba ba ba");
- }
- }
- Public class Machinegun extends Abstractgun {
- @Override
- Public void shoot () {
- SYSTEM.OUT.PRINTLN (" machine gun shot: the clatter of the clatter");
- }
- }
- Public class Soldier {
- //Have a gun
- Private Abstractgun AG;
- Public Abstractgun Getag () {
- return AG;
- }
- Public void Setag (Abstractgun AG) {
- this. AG = AG;
- }
- //Kill
- Public void Killenemy () {
- System.out.println (" soldiers on Battlefield kills ");
- Ag.shoot ();
- }
- }
- Public class Client {
- Public Static void Main (string[] args) {
- //Create a soldier
- Soldier s = new Soldier ();
- //Give a gun
- //s.setag (New Handgun ());
- //s.setag (New Rifle ());
- S.setag (new machinegun ());
- //Battle kills
- S.killenemy ();
- System.out.println ("--------------");
- //Create Sniper Object
- Snipper Sanmao = new snipper ();
- //Give Sniper sniper rifle
- Sanmao.setaug (new ());
- //Create parent class down transformation as parameter
- //sanmao.setaug (Rifle ());//java.lang.ClassCastException: There is no such thing as how to go down to the transition .
- //Kill the enemy
- Sanmao.killenemy ();
- }
- }
The Solider soldier class does not have to know which type of gun (subclass) was passed in when writing the program.
Precautions 1
It is important to use the parent class or interface when calling other classes in the class, and if the parent class or interface cannot be used, the design of the class has violated the LSP principle.
Inheritance is telling you to have the methods and properties of the parent class, and then you can override the parent class's methods.
However, the following question should be considered in the specific application scenario: Whether the subclass can fully implement the parent class's business.
Precautions 2
If a subclass cannot fully implement a method of the parent class, or if some of the methods of the parent class have "distorted" in the subclass, it is recommended that you break the parent-child inheritance relationship and replace the inheritance with dependencies, aggregation, composition, and so on.
2. Subclasses can have their own personalities
Subclasses can of course have their own behavior and appearance, that is, methods and properties.
Sometimes it takes a direct method parameter to pass the subclass directly, which may not require polymorphism, but this is relatively rare.
From the principle of the Richter substitution, it is not possible for the parent class to appear where there are subclasses.
3. Input parameters can be magnified when overriding or implementing a method of the parent class
The input parameter in the method is called the precondition, the principle of "contract first".
The preconditions for a method in a subclass must be the same (overridden) or looser (overloaded) as the pre-condition of the overridden method in the superclass.
4. Output can be scaled down when you overwrite or implement a method of the parent class
The return value of a method of a parent class is a type T, and the return value of the same method (overloaded or overridden) of the subclass is S,
Then the Richter substitution principle requires s to be less than or equal to T, that is, either s and T are the same type, or S is a subclass of T
Rewrite
The input parameters of the method with the same name as the parent class and subclass are the same, and the range value of the two methods of the subclass method returns the value s less than or equal to the parent class method return value T.
Overload
The input parameter type or number of the required method is not the same, the input parameter of the subclass is wider than or equal to the input parameter of the parent class
Ensure that the parent class is replaced with a subclass, and that the method with the same name as the parent class is not called.
Summarize
The purpose of using the Richter replacement principle is to enhance the robustness of the program and to maintain very good compatibility when the version is upgraded. Even if you add subclasses, the original subclasses can continue to run.
In the actual project, each sub-class corresponds to different business meanings, using the parent class as the parameter, passing different subclasses to complete different business logic, perfect!
2.3 Best Practices
In the project, the use of the Richter replacement principle, as far as possible to avoid sub-category "Personality", once the subclass has "personality",
The relationship between this subclass and the parent class is very difficult to reconcile, the sub-class as the parent class, the subclass of the "personality" is obliterated-wronged point;
The use of the handle class as a single business will make the coupling between the code confusing-a lack of standards for class substitution.
"Zen of Design Pattern" 2nd chapter on the Richter scale substitution principle