在阅读了这篇post后,我想我大部分都了解LSP和大部分的例子,但我不能说我对我的许多继承实例的经验100%肯定,因为它似乎有许多例子确实违反了LSP,并且在覆盖行为时似乎很难。
例如,考虑以下简单的继承演示,取自Head First Object Oriented Analysis & Design。他们是否违反了LSP子类的LSP?
public class Airplane {
private int speed;
public void setSpeed(int speed) {
this.speed = speed;
}
public int getSpeed() {
return speed;
}
}
public class Jet extends Airplane {
private static final int MULTIPLIER=2;
/**
* The subclass can change behaviour of its superclass, as well as call the
* superclass's methods. This is called overriding the superclass's behaviour
*/
public void set setSpeed(int speed) {
super.setSpeed(speed * MULTIPLIER);
}
public void accelerate() {
super.setSpeed(getSpeed() * 2);
}
}
在设置速度之后,使用对基类Airplane实例的引用的客户端可能会惊讶地发现,在传递Jet对象的实例后,它的速度是预期的两倍。是不是Jet改变了setSpeed()方法的后置条件,从而违反了LSP?
E.g。
void takeAirplane(Airplane airplane) {
airplane.setSpeed(10);
assert airplane.getSpeed()==10;
}
如果takeAirplane传递对Jet对象的引用,这将明显失败。 在我看来,当“覆盖超类的行为”时,很难不违反LSP,但这是继承的主要/理想特征之一!
有人可以解释或帮助澄清这一点吗?我错过了什么吗?
答案 0 :(得分:1)
[Liskov替换原则]指出,在计算机程序中,如果S是T的子类型,则类型T的对象可以用类型S的对象替换(即,类型S的对象可以替换类型的对象T)不改变该程序的任何理想属性(正确性,执行任务等)。
对于Jet而言,它的速度是违反LSP的两倍 - 它失败了setSpeed(getSpeed(x))==x
Liskov替换原则说,如果程序的正确性没有改变,可以修改派生类中的行为。它对您在派生类中所做的更改施加了限制。