S.O.L.I.D原则
中的L:Liskov Substitution Principle(LSP)
,里氏替换原则。如果只看上面图片中的描述,能让大部分人直接懵逼😄
我们还是来看看相对通俗点儿的定义。 里氏替换原则(Liskov Substitution Principle,LSP)可以解释为:
派生类型(子类)必须能够替换掉它们的基类型(父类)。
这个解释对于了解"继承"的小伙伴来说,显得理所当然。
但实际情况是:不是因为有了“继承”特性,里氏替换才有意义;而是因为有了里氏替换原则,才规范了“继承”特性的使用。
PS:小二哥可能表述得有点怪。不要慌,往下看!
上一篇文章中,我们提到开闭原则的最佳实践之一是抽象化。有了抽象,我们就可以基于抽象写一些具体的实现类了--这就是基类(父类)和派生类(子类)的继承关系。
好啦!问题来啦~ 请问“这个继承关系可以随便使用吗?”
从语法上来说,怎么用 extends
关键字来实现父子类关系都可以!但从业务逻辑上看,这是有很大问题的。比如下面这个例子。
我们有个 Dog 类。
public abstract class Dog {
void bark() {
System.out.println("狗叫");
}
public abstract void work();
}
现在,我们基于 Dog 类实现牧羊犬。
public class ShepherdDog extends Dog {
@Override
public void work() {
System.out.println("放羊!");
}
}
注意看,现在我定义Cat类,并继承Dog类
public class Cat extends Dog {
@Override
void bark() {
System.out.println("猫叫!");
}
@Override
public void work() {
System.out.println("抓老鼠!");
}
}
这里,我不仅重写了 work() 方法,还重写了 bark() 方法。因为,你没法让猫叫出狗叫声。但我重写了,对于 Cat 类来说,行为上是正确的。
好了!突然有一天,隔离邻居出远门,喊你给他条 Dog 帮他看家护院。不考虑 Dog 的品种,是 Dog 就行。请问,你是给邻居 ShepherdDog 还是 Cat?
只看基类 Dog 类型来说,基于里氏替换原则,你既可以给 ShepherdDog,又可以给 Cat。但理性告诉你,你不能给 Cat。因为,你把 Cat 给邻居,邻居会觉得你在鄙视他:咋的?古有指鹿为马,今有“借狗给猫”?
小伙伴们,肯定就会说啦:Cat 和 Dog 是两种动物了,肯定不能使用继承关系啦~
这个说法是对的。但对于我们面向对象编程过程中,尤其是在“继承”关系中,我们考虑的是“替换性”。Cat 不能替换 Dog, 因此,我们不能让 Cat extends Dog
。
同样,网络上经典的例子:正方形不是长方形的子类,也是如此。
大多数小伙伴觉得正方形可以继承长方形
,是因为把长和宽设置为一样就成正方形了。代码语法层面上很好实现。
问题在于,如果一个程序需要长方形进行面积计算时,你用正方形来替代,计算出的结果就和预期不符了。PS:大家可以上网搜一下这个例子,小二哥这里就不啰嗦啦~
由之前的例子可知,我们可以用里氏替换原则
来规范继承关系的实现是否合理。 如果子类可以替换它的父类,那么这个继承关系就是🆗的。
另外,里氏代换原则
是对“开闭原则”的补充。上一篇中,“开闭原则”的实践技巧中就是抽象化,这其实就是抽象出基类。而什么情况下能对这个基类进行具体实现呢?满足里氏代换原则,你就可以基于基类进行具体实现。
为什么里氏代换原则这么重要,小伙伴们理解了吗?
扫码关注腾讯云开发者
领取腾讯云代金券
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. 腾讯云 版权所有