Introduction
The Liskov Substitution Principle states that if you have a base class (in this case, Bike) and derived classes (MotorCycle
and Bicycle
), the derived classes should be able to replace the base class without causing issues.
General
If you have a family of objects where one is the main type and others are variations, you should be able to use the variations wherever you use the main type, without things going haywire.” It’s all about making sure that new types don’t mess up how the old type worked.
Bike.java
interface Bike{
void turnOnEngine();
void accelerate();
}
MotorCycle.java
class MotorCycle implements Bike{
boolean isEngineOn;
int speed;
@Override
public void turnOnEngine(){
//turn on engine
isEngineOn = true;
}
@Override
public int accelerate(){
//increase the speed
speed = speed + 10;
}
}
Bicycle.java
class Bicycle implements Bike{
boolean isEngineOn;
int speed;
@Override
public void turnOnEngine(){
throw new AssertionError("there is no engine");
}
@Override
public int accelerate(){
//increase the speed
speed = speed + 10;
}
}
In the case of Bicycle
, turnOnEngine()
is implemented to throw an error because bicycles don’t have engines.
This implementation contradicts the behavior expected from the base interface.
In a nutshell, the Liskov Substitution Principle encourages you to ensure that derived classes can be used interchangeably with the base class, following the same behavior. In this example, the Bicycle
class breaks this principle by providing behavior that is not consistent with the expected behavior defined in the base class (Bike
) interface.
classDiagram
EngineVehicle <|-- MotorCycle
NonEngineVehicle <|-- Bicycle
class EngineVehicle {
<<interface>>
+turnOnEngine()
+accelerate()
}
class NonEngineVehicle {
<<interface>>
+accelerate()
}
class MotorCycle {
+boolean isEngineOn
+int speed
+turnOnEngine()
+accelerate()
}
class Bicycle {
+int speed
+accelerate()
}