里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的 "面向对象技术的高峰会议(OOPSLA)"上发表的一篇文章《数据抽象和层次》里提出来的,她提出:继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)。里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对实现抽象化的具体步骤的规范。 根据上述理解,对里氏替换原则的定义可以总结如下: ♞ 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法 ♞ 子类中可以增加自己特有的方法 ♞ 子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松 ♞ 子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
① 里氏替换原则是实现开闭原则的重要方式之一。 ② 它克服了继承中重写父类造成的可复用性变差的缺点。 ③ 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。 ④ 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。
如下图所示,AK47 与 98K 继承了枪械这个类,继承了其开火攻击的方法,但是玩具枪继承枪械类的时候重写开火方法,将攻击改为了发光。士兵在拿武器的时候开到玩具枪确实是继承了 Firearms 类,也有 fire 方法,就直接拿了玩具枪,结果在交战时它发光了!!这不是坑吗,有可能会造成全线崩溃。
在开发中,此时已经发现了业务调用出现了问题,我们尝试用 instanceof 判断是否是玩具枪来解决,可以发现虽然可以解决但是不划算,万一又来一个玩具枪二号又要重新解决,这种方案直接 pass;二号方案就是直接将玩具枪从 Firearms 剥离出来,新建一个父类 ToyGun,建立委托关系,外形等交给 Firearms 负责,发光交给新类 ToyGun。
只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。比方说,猫是继承动物类的,以动物的身份拥有吃、喝、跑、叫等行为,可当某一天,我们需要狗、牛、羊也拥有类似的行为,由于它们都是继承于动物,所以只需要更改实例化的地方,程序其他处不需要改变。满足里氏替换原则的子类可以替换父类,但是不能反过来使用父类代替子类。 里氏替换原则诞生的目的就是加强程序的健壮性,同时版本升级也可以做到非常好的兼容性,增加子类,原有的子类还可以继续运行。在我们项目实施中就是每个子类对应了不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑,非常完美!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有