我试图理解Liskov替换原理,我有以下代码:
class Vehicle {
}
class VehicleWithDoors extends Vehicle {
public void openDoor () {
System.out.println("Doors opened.");
}
}
class Car extends VehicleWithDoors {
}
class Scooter extends Vehicle {
}
class Liskov {
public static void function(VehicleWithDoors vehicle) {
vehicle.openDoor();
}
public static void main(String[] args) {
Car car = new Car();
function(car);
Scooter scooter = new Scooter();
//function(scooter); --> compile error
}
}
我不确定这是否违反了它。原理是,如果你有一个类S的对象,那么你可以用另一个类T的对象来代替它,其中S是T的一个子类。但是,如果我写了
Vehicle vehicle = new Vehicle();
function(vehicle);
这当然会产生编译错误,因为Vehicle类没有openDoor()方法。但这意味着我不能用它们的父类Vehicle替换VehicleWithDoors对象,这似乎违反了原则。那么这个代码是否违反了它?我需要一个好的解释,因为我似乎不明白。
扩展类或接口时,新类仍然是它扩展的类型。对此进行推理的最简单方法(IMO)是将子类视为超类的一种特殊类型。所以它仍然是超类的一个实例,还有一些额外的行为。
例如,带车门的车辆仍然是
车辆
,但它也有车门。滑板车也是一种交通工具,但它没有门。如果您有打开车门的方法,则车辆必须有车门(因此,当您将踏板车传递给它时会出现编译时错误)。同样,对于接受某个类的对象的方法,您可以传递作为其子类实例的对象,该方法仍然可以工作。
就实现而言,您可以安全地将任何对象强制转换为其超类型之一(例如,汽车和
滑板车
到车辆
,汽车
到带门车辆
),但不能反过来(如果您进行一些检查并明确地强制转换,则可以安全地执行此操作)。
你倒过来了。该原则规定,“如果S
是T
的子类型,则程序中T
类型的对象可以替换为S
类型的对象,而不改变该程序的任何期望属性”。
基本上,车辆
应该在车辆
工作的地方工作。这显然并不意味着车辆
应该在车辆与门
工作的地方工作。换句话说,您应该能够在不影响程序正确性的情况下用专门化替换泛化。
示例冲突是一个ImmutableList
扩展一个定义add
操作的List
,其中不可变实现抛出异常。
js lang-js prettyprint-override">class List {
constructor() {
this._items = [];
}
add(item) {
this._items.push(item);
}
itemAt(index) {
return this._items[index];
}
}
class ImmutableList extends List {
constructor() {
super();
}
add(item) {
throw new Error("Can't add items to an immutable list.");
}
}
我试图通过反复阅读维基百科条目来确定我对上述原则的理解。 撇开仍然让我悲伤的协变和逆变的概念不谈,wikipedia还提到超类型的不变量必须保留在子类型和历史约束或历史规则中。基于最后两个概念,我提出了一个小例子: 所以我的问题是:基于上述两个概念,我用这个例子是否违反了原则?若否,原因为何? 事先非常感谢。
存在无法写入或查找的流派生类这一事实是否违反了Liskov替换原则? 例如,无法查找NetworkStream,如果调用方法,它将抛出。 还是因为存在标志就可以了? 考虑到众所周知的继承自的例子...将标志和添加到是否可以解决问题? 这难道不是打开了通过添加旗帜来解决问题的大门吗?
我在派生类中重写了带有附加先决条件的虚拟函数。这是快照- 如果我理解正确的话,这里的代码通过附加一个先决条件打破了Liskov替换-IsImmediateProcess和其他日期检查。对吗?或者一个被重写的函数调用一个基函数,然后向它添加自己的行为,这样可以吗? 我不能将重写方法中由初始过程类型引入的条件移动到基本类型,因为它是特定于初始过程的。 在这种情况下,如果派生类重写行为并希望在不违反Li
LSP定义指出,如果S是T的子类型,则程序中T类型的对象可以替换为S类型的对象,而不改变该程序的任何期望属性。 子类型中的前提条件不能加强 例如,我有下面的类,这是违反(在子类型中不能加强前提条件)。我正试图把我的头绕在这上面,请有人提供一个好的例子来理解它。
来自维基百科, Liskov的行为子类型概念定义了对象的可替代性概念;也就是说,如果S是T的子类型,则程序中T类型的对象可以替换为S类型的对象,而不改变该程序的任何期望属性(例如正确性)。 假设以下类层次结构: 基本抽象类-。它有一个只读属性,在后继程序中被重写。 基类的继承者-,它重写并返回灰色。 Cat的继任者-,它覆盖并返回带条纹的。 然后我们声明一个方法,参数类型为(不是)。 向该方法发送