里氏替换原则(Liskov Substitution Principle,简称LSP)是面向对象设计中的一个原则,它规定如果一个类型是另一个类型的子类型,那么应该可以替换掉父类型的对象而不影响程序的正确性。简而言之,子类型必须能够替换其基类型。
反例:
class Rectangle {
protected int width;
protected int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int calculateArea() {
return width * height;
}
}
class Square extends Rectangle {
@Override
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
@Override
public void setHeight(int height) {
super.setHeight(height);
super.setWidth(height);
}
}
在这个例子中,Square 类继承自 Rectangle 类,但是为了满足正方形的特性,覆写了父类的 setWidth 和 setHeight 方法。这样的设计违反了里氏替换原则,因为使用基类 Rectangle 的代码在替换成子类 Square 后可能导致错误。例如:
Rectangle rectangle = new Square();
rectangle.setWidth(5);
rectangle.setHeight(10);
int area = rectangle.calculateArea(); // 预期结果是50,但实际结果是100
在这个例子中,虽然使用 Rectangle 类型的引用指向了 Square 类的对象,但由于 Square 类在设置宽度和高度时有特殊处理,导致最终的计算面积结果不符合预期。
正例:
class Shape {
// 定义通用的形状类
}
class Rectangle extends Shape {
protected int width;
protected int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int calculateArea() {
return width * height;
}
}
class Square extends Shape {
protected int side;
public void setSide(int side) {
this.side = side;
}
public int calculateArea() {
return side * side;
}
}
在正例中,Rectangle 和 Square 都继承自通用的形状类 Shape,并且都提供了各自计算面积的方法。这样,可以保证在使用基类 Shape 的代码中,可以用任何子类对象替代而不引起错误。这符合里氏替换原则,子类可以替代父类而不产生意外行为。