里氏替换原则 (LSP)
使类可替代子类
LSP 声明任何子类都应该可以替代其基类。[9]这意味着如果 B extends
A,那么我们应该能够在我们使用 A 的任何地方使用 B,而无需改变任何功能。我会直言不讳:我们只是没有真正在 React 中使用它。如今,无论如何,所有代码都应该使用类上的钩子来编写,因此类在现代 React 代码中的作用应该非常小。本节为后代而存在,但这肯定是应用于前端设计的不太相关的原则之一。[10]
为了说明这个原则,假设我们有一些基类,Vehicle
它有一个附加到它的方法,它会发出汽车引擎的噪音。我们可以扩展一个由此调用的类,这很好,因为汽车有引擎噪音。但是,如果通过扩展创建,我们必须隐藏此方法,因为自行车没有引擎噪音,因此如果有人尝试调用,我们将抛出错误。engineNoise()
Car
Bicycle
Vehicle
engineNoise()
engineNoise()
Bicycle
class Vehicle {
constructor(wheels){
this.wheels = wheels;
}
engineNoise(){
console.log("VROOM VROOM");
}
};
class Car extends Vehicle {
numWheels(){
console.log(this.wheels);
}
};
class Bicycle extends Vehicle {
numWheels(){
console.log(this.wheels);
}
// Bicycle has no engine, therefore we must throw an error
// if someone attempts to access this property on a bicycle.
engineNoise(){
throw new Error("I have no engine.")
}
}
function makeVehicleEngineNoise(vehicle){
vehicle.engineNoise();
}
const car = new Car(4);
const bicycle = new Bicycle(2);
makeVehicleEngineNoise(car); // "VROOM VROOM!"
makeVehicleEngineNoise(bicycle); // ERROR: I have no engine.
如果我们尝试用,的子类调用,我们会得到一个错误(我们需要添加一个错误,因为我们不希望人们能够在自行车上调用)。这意味着我们无法替换with的每个实例并保持相同的功能。如果我们想这样做,我们将需要改变我们的类,使其只包含所有可能的子类都具有的属性/方法。例如,如果我们假设每辆车都有轮子,我们可以修改我们的类并安抚 LSP:makeVehicleEngineNoise()
Vehicle
Bicycle
engineNoise
Vehicle
Bicycle
Vehicle
Vehicle
class Vehicle {
constructor(wheels){
this.wheels = wheels;
}
numWheels(){
console.log(this.wheels);
}
};
class Car extends Vehicle {
engineNoise(){
console.log("VROOM VROOM");
}
};
class Bicycle extends Vehicle {
sayFrameMaterial{
console.log("I am made from carbon fibre!")
}
}
function sayNumWheels(vehicle){
vehicle.numWheels();
}
const car = new Car(4);
const bicycle = new Bicycle(2);
sayNumWheels(car); // 4
sayNumWheels(bicycle); // 2
如果您从一个类扩展,请确保基类是通用的,因为它是每个子类的真实表示。
发表评论
所有评论(0)