文章目录
概要
里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
理解说明
- 任何父类可以出现的地方,子类一定可以出现。通俗来讲,就是,子类可以
扩展
父类的功能,但是不能改变
父类原有的功能;也就是说,除了添加
新方法,尽量不要重写
父类的方法。 - 通过
重写
父类的一些方法来完成新的功能,这样写起来虽然比较简单,但是会导致,整个继承体系的可复用性会变差,特别是运用多态
比较频繁时,程序出错的概率会非常大!
案例 – 正方形不是长方形
Part I – 不符合LSP 正方形(子类)继承长方形(父类)
首先创建正方形和长方形的类
// 长方形类
public class Rectangle {
private double length;
private double width;
// 相应的getter、setter方法
}
// 正方形类
public class Square extends Rectangle{
// 重写了父类的方法
@Override
public void setLength(double length) {
super.setLength(length);
super.setWidth(length);
}
@Override
public void setWidth(double width) {
super.setWidth(width);
super.setLength(width);
}
}
由代码可见,正方形类
重写了长方形类
的两个set方法,用于将正方形的长宽设置成同一个值,那么我们在调用的时候,就会出现一些问题
// 首先定义两个方法
// 如果长方形的长 小于等于 宽,那么给长重新赋值为 长 + 1
public static void resize(Rectangle rectangle) {
//判断宽比长小,进行扩宽
while (rectangle.getLength() <= rectangle.getWidth()) {
rectangle.setLength(rectangle.getLength() + 1);
}
}
// 打印长方形的长和宽
public static void printLengthAndWidth(Rectangle rectangle) {
System.out.println(rectangle.getLength());
System.out.println(rectangle.getWidth());
}
// 然后开始调用
public static void main(String[] args) {
Rectangle rectangle = new Rectangle();
rectangle.setWidth(20);
rectangle.setLength(10);
//扩长
resize(rectangle);
printLengthAndWidth(rectangle);
System.out.println("============================");
Square s = new Square();
s.setLength(10);
resize(s);
printLengthAndWidth(s);
}
--------结果输出:
20.0
21.0
============================
此处会卡住,因为正方形的setLength方法会给长宽重新赋值,所以无限循环
Part I – 结论
运行这段代码就会发现,把一个长方形作为参数传入resize方法中,能实现我们的预期;但如果传入的是一个正方向,那么代码会一直运行下去,直至系统产生溢出错误。所以可以得出结论:在resize方法中,Rectangle类型的参数是不能被Square类型的参数所代替,如果进行了替换就得不到预期结果。因此,Square类和Rectangle类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立,正方形不是长方形。那么我们如何改进呢?
Part II – 符合LSP
我们需要重新设计他们之间的关系。
抽象出来一个四边形接口(Quadrilateral)
,让Rectangle类
和Square类
实现Quadrilateral接口
// 首先抽象出一个四边形接口
public interface Quadrilateral {
//获取长
double getLength();
//获取宽
double getWidth();
}
-------------------------------------------------------------------------------------
// 长方形类和正方形类,都实现这个接口
public class Rectangle implements Quadrilateral{
private double length;
private double width;
@Override
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
}
-------------------------------------------------------------------------------------
public class Square implements Quadrilateral {
//边长
private double side;
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
@Override
public double getLength() {
return side;
}
@Override
public double getWidth() {
return side;
}
}
这样,长方形和正方形可以分别实现自己的get方法,那么我们在相同的调用时,就可以只针对长方形进行扩长,参数为长方形类
,对打印的方法,参数为四边形接口
,这样就可以实现里氏代换原则
// 如果长方形的长 小于等于 宽,那么给长重新赋值为 长 + 1
public static void resize(Rectangle rectangle) {
//判断宽比长小,进行扩宽
while (rectangle.getLength() <= rectangle.getWidth()) {
rectangle.setLength(rectangle.getLength() + 1);
}
}
// 打印长方形的长和宽
public static void printLengthAndWidth(Rectangle rectangle) {
System.out.println(rectangle.getLength());
System.out.println(rectangle.getWidth());
}
// 开始调用
public static void main(String[] args) {
Rectangle r = new Rectangle();
r.setLength(10);
r.setWidth(20);
resize(r);
printLengthAndWidth(r);
System.out.println("============================");
Square s = new Square();
s.setSide(10);
printLengthAndWidth(s);
}
------------------运行结果:
21.0
20.0
============================
10.0
10.0
标签:软件设计,代换,void,长方形,Rectangle,原理篇,double,public,rectangle
From: https://blog.csdn.net/hitman_may_cry/article/details/141932172