Liskov Substitution Principle
About 866 wordsAbout 3 min
2025-03-27
Definition
All places where references are accumulated must be able to transparently use objects of their derived classes.
Simply put, anywhere in the code where a parent class object is used, a child class object can be directly used to directly replace it and the function will be normal.
Function
There is a function P1, which is completed by class A. Now it is necessary to expand function P1, and the expanded function is P, where P consists of the original function P1 and the new function P2. The new function P is completed by the subclass B of class A. When subclass B completes the new function P2, it may cause the original function P1 to fail.
If we follow the Liskov Substitution Principle, we can ensure that the code will not fail.
Four meanings of Liskov Substitution Principle
Subclasses can implement abstract methods of parent classes, but cannot override non-abstract methods of parent classes.
Subclasses can implement abstract methods of parent classes, but cannot override non-abstract methods of parent classes. All implemented methods in parent classes (relative to abstract methods) are actually setting a series of specifications and contracts. Although it does not force all subclasses to comply with these contracts, if subclasses arbitrarily modify these non-abstract methods, it will damage the entire inheritance system.
Subclasses can have their own personality.
While inheriting parent class properties and methods, each subclass can also have its own personality and expand its own functions based on the parent class. As mentioned earlier, when the function is expanded, the subclass should try not to rewrite the parent class method, but write another method, so the above code is changed to make it conform to Liskov Substitution Principle.
Input parameters can be enlarged when overriding or implementing parent class methods.
When a subclass method overloads a parent class method, the method's precondition (i.e., the method's formal parameters) should be looser than the parent class method's input parameters.
The output result can be reduced when overriding or implementing the parent class method.
When a subclass method implements the parent class's abstract method, the method's postcondition (i.e., the method's return value) should be stricter than the parent class.
Advantages of Liskov Substitution Principle
- Ensures the reusability of the parent class.
- Reduces system errors and prevents misoperation.
- Does not destroy the inheritance mechanism.
- Enhances the robustness of the program, and version upgrades can also maintain very good compatibility.
Even if subclasses are added, the original subclasses can continue to run. In actual projects, each subclass corresponds to a different business meaning, using the parent class as a parameter to pass different subclasses to complete different business logic.
Disadvantages of Liskov Substitution Principle
Inheritance is invasive.
As long as you inherit, you must have all the properties and methods of the parent class.
Reduced code flexibility.
Subclasses have the properties and methods of the parent class, which will increase constraints.
Enhanced coupling.
When the constants, variables, and methods of the parent class are modified, the modification of the subclass must be considered.
Implementation method
If the relationship between two classes A and B violates the Liskov substitution principle (assuming A is the parent class), you can choose the following refactoring scheme:
- Create a new abstract class C as the parent class of A and B, and move the common comfort of A and B to C.
- Change the inheritance relationship to an association relationship.
Example
The following shows one of the refactoring methods, which changes the inheritance relationship between two classes to an association relationship.
Let's consider the example between athletes and bicycles, each athlete has a bicycle.
Counter Example
class Bike {
public:
void Move();
void Stop();
void Repair();
protected:
int ChangeColor(int);
private:
int mColor;
};
class Player: private Bike
{
public:
void StartRace();
void EndRace();
protected:
int CurStrength ();
private:
int mMaxStrength;
int mAge;
};
Positive Example
class Bike {
public:
void Move();
void Stop();
void Repair();
protected:
int ChangeColor(int);
private:
int mColor;
};
class Player
{
public:
void StartRace( );
void EndRace( );
protected:
int CurStrength ( );
private:
int mMaxStrength;
int mAge;
Bike * abike;
};
Obviously, we changed Bike
from the base class of Player
to a part of it.
Summary
As one of the three major features of object-oriented programming, inheritance brings great convenience to program design, but also brings disadvantages. For example, using inheritance will make the program invasive, reduce the portability of the program, and increase the coupling between objects. If a class is inherited by other classes, when this class needs to be modified, all subclasses must be considered, and after the parent class is modified, all functions involving subclasses may fail.
The purpose of the Liskov Substitution Principle is to enhance the robustness of the program and maintain very good compatibility during version upgrades.
References for this article
Contributors
Changelog
270fc
-feat(docs): add solid principles serieson
Copyright
Copyright Ownership:dingyuqi
License under:Attribution-NonCommercial-NoDerivatives 4.0 International (CC-BY-NC-ND-4.0)