里氏代换原则
任何基类可以出现的地方,子类一定可以出现
通俗来讲,子类继承父类的时候,除了添加新的方法完成新增功能外,尽量不要去重写父类的方法。
如果你重写了父类的方法,整个继承体系的可复用性就会变差,尤其是运用多态比较频繁的时候,程序运行出错的概率会非常大!
🌰举个栗子
❌错误示范
在数学中,正方形是一个长和宽相等的长方形,所以我们开发一个与几何图形相关的软件系统,就可以直接让正方形继承自长方形
长方形类:
//Rectangle.class
private int length;
private int width;
public void setLength(int length) {
this.length = length;
}
public void setWidth(int width) {
this.width = width;
}
//省略getter
正方形类继承自长方形类,但是这里为了使长宽相同,重写了父类的setter:
//Square.class
private int length;
private int width;
public void setLength(int length) {
//保证了长宽相同
this.length = length;
this.width = width
}
public void setWidth(int width) {
//保证了长宽相同
this.width = width;
this.length = length;
}
现在我们有一个需求:为长方形实例拓宽,直到宽比长更大:
//Test.class
Square sq = new Square();
sq.setLength(20);
public void resize(Rectangle rect) {
while(rect.getLength() >= rect.getWidth()) {
rect.setWidth(rect.getWidth()++);
}
}
方法中进行判断,当实例的宽比长小,就给宽++,最终实现宽大于长的目的。
如果传入的是长方形,则可以正常执行,但如果传入了正方形,正方形的宽和高都在不停变化,始终保持一致,这样就会导致无限循环而报错。
以上就是错误的示范,错误原因就在于正方形类重写了父类长方形中的getter,导致出现错误。
✔正确示范
由错误案例我们就能得出一个结论:正方形不能简单地抽象为长方形,需要将他们分而治之。
我们重新设计他们之间的关系。抽象出来一个四边形接口(Quadrilateral),让Rectangle类和Square类实现Quadrilateral接口:
这样resize方法中只能传入长方形对象,而不能传入正方形对象,就避免了传入正方形进入死循环的问题,完美的符合了里氏代换原则!