Appearance
里氏替换原则
- 里氏替换原则是面向对象涉及的基本原则之一
- 里氏替换原则:任务基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类原有的功能。换句话说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法
- 如果通过重写父类的方法来完成新的功能,这样写起来很简单,但是整个继承计息的可复用性会比较差,特别是运用多态比较频繁时,程序出错的概率非常大
例:
在数学理念关于中,正方式属于长方形,即长宽相等的特殊长方形。所以,我们开发的一个与几何图形相关的团建系统,就可以顺利成章的让正方形继承长方形
原始方案
长方形
java
package com.huangjiliang.design.heima.principle.demo2;
import lombok.Data;
/**
* 长方形实体类
*/
@Data
public class Rectangle {
/**
* 长度
*/
private Long length;
/**
* 宽度
*/
private Long width;
}
长方形
java
package com.huangjiliang.design.heima.principle.demo2;
import lombok.Getter;
/**
* 正方形实体类,继承长方形
*/
@Getter
public class Square1 extends Rectangle{
@Override
public void setLength(Long length) {
super.setLength(length);
super.setWidth(length);
}
@Override
public void setWidth(Long width) {
super.setWidth(width);
super.setLength(width);
}
}
演示主类
java
package com.huangjiliang.design.heima.principle.demo2;
public class RectangleDemo {
public static void resize(Rectangle rectangle) {
while (rectangle.getWidth() <= rectangle.getLength()) {
rectangle.setWidth(rectangle.getWidth() + 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.setLength(40L);
rectangle.setWidth(30L);
resize(rectangle);
printLengthAndWidth(rectangle);
// 正方形
Square1 square1 = new Square1();
square1.setLength(30L);
resize(square1);
printLengthAndWidth(square1);
}
}
UML图
分析
运行以上main方法时候,发现程序一致在运行,直到内存溢出报错
- resize方法传入普通的长方形实体类,当宽度小于长度时候,进入while循环,宽度+1,当宽度大于长度之后,退出循环,可以得到预期效果
- resize方法传入特殊情况的长方形实体类(即正方形),因为正方形长款时相等的,会一直在while死循环,无法推出,导致内存溢出
- 所以:只有普通的长方形是适合resize这个方法,其子类square不适合。即Rectangle类型的参数是不能Square类型的参数所替代,即进行了替换得不到预期的结果。因此Square和Rectangle类之间的继承关系违反了里氏替换原则,他们之间的继承关系不成立,正方形不是长方形
改进方案
抽象一个四边形接口(Quadrilateral),让Rectangle和Square类实现Quadrilateral接口
四边形
java
package com.huangjiliang.design.heima.principle.demo2.improve;
public interface Quadrilateral {
Long getLength();
Long getWidth();
}
长方形
java
package com.huangjiliang.design.heima.principle.demo2.improve;
/**
* 长方形实体类,实现四边形
*/
public class Rectangle implements Quadrilateral {
/**
* 长度
*/
private Long length;
/**
* 宽度
*/
private Long width;
@Override
public Long getLength() {
return length;
}
public void setLength(Long length) {
this.length = length;
}
@Override
public Long getWidth() {
return width;
}
public void setWidth(Long width) {
this.width = width;
}
}
正方形
java
package com.huangjiliang.design.heima.principle.demo2.improve;
import lombok.Data;
/**
* 正方形实体类,实现四边形
*/
@Data
public class Square implements Quadrilateral {
private Long size;
@Override
public Long getLength() {
return size;
}
@Override
public Long getWidth() {
return size;
}
}
演示类
java
package com.huangjiliang.design.heima.principle.demo2.improve;
/**
* 演示里氏替换原则原始方式【正方形继承长方形违反里氏替换原则】
*/
public class RectangleDemo {
/**
* resize方法只适合普通的长方形,不能传入特殊四边形的正方形
* @param rectangle
*/
public static void resize(Rectangle rectangle) {
while (rectangle.getWidth() <= rectangle.getLength()) {
rectangle.setWidth(rectangle.getWidth() + 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.setLength(40L);
rectangle.setWidth(30L);
resize(rectangle);
printLengthAndWidth(rectangle);
}
}
UML图
分析
- 改进后的方案的resize方法只适合普通长方形,不适合特殊四边形的正方形