Liskov Substitution Principle 里氏替换原则
简介
定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型,
定义扩展:一个软件实体如果使用一个父类的话,那一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替代父类对象,而程序逻辑不变。
主要核心思想
强调只和朋友交流,不和陌生人说话
朋友:出现在成员变量、方法的输入、输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
引申意义:子类可以扩展父类的功能,但不能改变父类原有的功能
含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
含义2:子类中可以增加自己特有的方法
含义3:当子类的方法重载父类的方法时,方法的前置条件(即方法的输入、入参)要比父类方法的输入参数更宽松
含义4:当子类的条件实现父类的方法时(重写、重载或实现抽象方法),方法的后置条件(即方法的输出、返回值)要比父类更严格或相等。
优点
- 约束继承泛滥,开闭原则的一种体现
- 加强程序的健壮性,同时变更时也可以做到非常好的兼容性提高程序性的维护性,扩展性。
- 降低需求变更时引入的风险
实践案例
类层面:正方形、长方形
方法层面:含义3
返回值层面:含义4
类层面:正方形、长方形
public interface QuadRangle {
Integer getHeight();
Integer getWidth();
}
public class Rectangle implements QuadRangle {
private Integer height;
private Integer width;
@Override
public Integer getHeight() {
return this.height;
}
@Override
public Integer getWidth() {
return this.width;
}
public void setHeight(Integer height) {
this.height = height;
}
public void setWidth(Integer width) {
this.width = width;
}
}
public class Square implements QuadRangle {
private Integer length;
@Override
public Integer getHeight() {
return this.length;
}
@Override
public Integer getWidth() {
return this.length;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
}
public class LspTest {
public static void resize(Rectangle rectangle) {
while (rectangle.getWidth() >= rectangle.getHeight()) {
rectangle.setHeight(rectangle.getHeight()+1);
System.out.println("Width:" + rectangle.getWidth() +",Height:"+ rectangle.getHeight());
}
}
public static void main(String[] args) {
// Rectangle rectangle = new Rectangle();
// rectangle.setHeight(10);
// rectangle.setWidth(20);
// resize(rectangle);
Square square = new Square();
square.setLength(20);
// resize(square);
}
}
上面类图与下面类图为代码编写的两种情况,一种是以长方形为父类,另一种是以正方形为父类
方法层面:含义3
public class Base {
// public void method(HashMap map) {
// System.out.println("执行父类HashMap参数的方法");
// }
public void method(Map map) {
System.out.println("执行父类Map参数的方法");
}
}
public class Child extends Base {
public void method(HashMap map) {
System.out.println("执行子类HashMap参数的方法");
}
// public void method(Map map) {
// System.out.println("执行子类Map参数的方法");
// }
}
public class MethodTest {
public static void main(String[] args) {
HashMap map = new HashMap();
Base base = new Child();
base.method(map);
}
}
当父类方法入参比子类大时,即父类 method 方法 入参为Map,而子类为HashMap
Base base = new Child(); base.method(map); 调用的是父类的 method 方法
Child base = new Child(); base.method(map); 调用的是子类的 method 方法
返回值层面:含义4
public abstract class Base {
public abstract Map getMap();
}
public class Child extends Base {
@Override
public HashMap getMap() {
HashMap hashMap = new HashMap();
System.out.println("执行子类的getMap()方法");
hashMap.put("msg", "执行成功");
return hashMap;
}
}
public class MethodReturnTest {
public static void main(String[] args) {
Base base = new Child();
Map map = base.getMap();
System.out.println(map.get("msg"));
}
}
父类方法返回值类型为Map,子类重写父类方法,修改其返回值类型为HashMap,测试运行成功