理论性知识 定义里氏替换原则,Liskov Substitution principle(LSP)。 抽象定义是下面这样的 如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。 通俗地解释一下 一个软件实体如果适用一个父类的话,那一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。 引申一下,如果子类替换父类,还必须保证程序逻辑不变,就必须满足以下几点。
优点加强程序的健壮性,同时变更时可以做到非常好的兼容性。 提高程序的维护性,扩展性,降低需求变更时引入的风险。
代码实战1 实现一个正方形继承长方形的场景,因为正方形是一种特殊的长方形。 定义一个长方形,如下图
定义一个正方形,如下图,重写了父类的方法。
最后执行测试方法,当宽大于等于高时,就改变宽和高。如下图
当用子类正方形替换父类时,程序就会进入无限循环,如下图
根据以上得出,子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
代码实战2 首先定义一个简单的父类,如下图
然后定义一个子类,子类的入参类型Map比父类的入参HashMap宽松,如下图
最后测试如下图
由测试结果可以看出,child类完全可以替换base类去执行。遵循了里式替换原则, 即当子类的方法重载父类的方法时,方法的前置条件(即方法的输入,入参)要比父类方法的输入参数更宽松。 代码实战3 还是定义一个简单的父类,方法返回类型为HashMap,如下图
定义一个子类,实现父类抽象方法时,返回值类型为Map,编译器就会直接报错,如下图
根据以上可以得出结论 当子类的方法实现父类的方法时(重写,重载或实现抽象方法),方法的后置条件(方法的输出,返回值)要比父类更严格或相等。 个人总结 一开始学习里式替换原则时,也是不明白。最后也是慢慢理解透的。总结起来就是 子类可以替换父类,替换后,不能改变程序的运行逻辑。 也欢迎大家在评论区留下自己的看法! |
|