前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >为什么一个类不能随意被继承?

为什么一个类不能随意被继承?

作者头像
程序视点
发布于 2023-09-13 04:39:56
发布于 2023-09-13 04:39:56
23700
代码可运行
举报
文章被收录于专栏:程序小小事程序小小事
运行总次数:0
代码可运行
今天我们来聊聊S.O.L.I.D原则中的L:Liskov Substitution Principle(LSP),里氏替换原则。

LSP 简介

如果只看上面图片中的描述,能让大部分人直接懵逼😄

我们还是来看看相对通俗点儿的定义。 里氏替换原则(Liskov Substitution Principle,LSP)可以解释为:

派生类型(子类)必须能够替换掉它们的基类型(父类)。

这个解释对于了解"继承"的小伙伴来说,显得理所当然。

但实际情况是:不是因为有了“继承”特性,里氏替换才有意义;而是因为有了里氏替换原则,才规范了“继承”特性的使用。

PS:小二哥可能表述得有点怪。不要慌,往下看!

上一篇文章中,我们提到开闭原则的最佳实践之一是抽象化。有了抽象,我们就可以基于抽象写一些具体的实现类了--这就是基类(父类)和派生类(子类)的继承关系。

好啦!问题来啦~ 请问“这个继承关系可以随便使用吗?”

从语法上来说,怎么用 extends 关键字来实现父子类关系都可以!但从业务逻辑上看,这是有很大问题的。比如下面这个例子。

LSP 反证示例

我们有个 Dog 类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class Dog {

    void bark() {
        System.out.println("狗叫");
    }

    public abstract void work();
}

现在,我们基于 Dog 类实现牧羊犬。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ShepherdDog extends Dog {

    @Override
    public void work() {
        System.out.println("放羊!");
    }
}

注意看,现在我定义Cat类,并继承Dog类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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:大家可以上网搜一下这个例子,小二哥这里就不啰嗦啦~

总结

由之前的例子可知,我们可以里氏替换原则来规范继承关系的实现是否合理。 如果子类可以替换它的父类,那么这个继承关系就是🆗的。

另外,里氏代换原则是对“开闭原则”的补充。上一篇中,“开闭原则”的实践技巧中就是抽象化,这其实就是抽象出基类。而什么情况下能对这个基类进行具体实现呢?满足里氏代换原则,你就可以基于基类进行具体实现。

为什么里氏代换原则这么重要,小伙伴们理解了吗?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-17 08:08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序视点 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OOAD之设计原则
衡量软件设计质量的首要标准是该设计是否能满足软件的功能需求。除了功能需求以外,还有很多衡量软件设计质量的标准,包括可读性、可复用性、可扩展性、可维护性等。
架构之家
2022/09/27
3320
OOAD之设计原则
设计原则:面向对象设计原则详解
我们在应用程序开发中,一般要求尽量两做到可维护性和可复用性。 应用程序的复用可以提高应用程序的开发效率和质量,节约开发成本,恰当的复用还可以改善系统的可维护性。而在面向对象的设计里面,可维护性复用都是以面向对象设计原则为基础的,这些设计原则首先都是复用的原则。遵循这些设计原则可以有效地提高系统的复用性,同时提高系统的可维护性。 面向对象设计原则和设计模式也是对系统进行合理重构的指导方针。
黄规速
2022/04/14
2.7K0
设计原则:面向对象设计原则详解
SOLID原则(OOD&OOP)
SOLID原则是面向对象编程和面向对象设计的头五大原则。学习及应用这五大原则可以构建一个易于维护和扩展的应用程序,我们一起看看到底是那五大原则。
小世界的野孩子
2019/09/11
1K0
软件架构设计原则之里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是指如果对每一个类型为T1的对象o1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
Tom弹架构
2021/10/24
4700
软件开发中的原则
一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。(Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.),即又定义有且仅有一个原因使类变更。
lyb-geek
2018/07/26
6070
软件开发中的原则
设计模式学习心得之前置知识 UML图看法与六大原则
统一建模语言(Unified Modeling Language,UML)是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。
Qiuner
2024/07/19
930
设计模式学习心得之前置知识 UML图看法与六大原则
一文搞懂SOLID原则(javascript)
SOLID 是面向对象编程重要的原则,javascript 作为面向对象开发的语言之一,掌握这些原则,可以写出更优雅的代码。
奋飛
2023/03/06
3360
软件架构设计原则--里氏替换原则
  里氏替换原则(Liskov Substitution Principle,LSP)是指,如果对每一个类型为T1的对象t1,都替换为类型为T2的对象t2,使得以T1定义的所有程序P在所有的对象t1都替换成t2时,程序P的行为没有发生变化,那么T2就是T1的子类型。   这个定义看上去比较抽象,我们重新理解一下。可以理解为一个软件实体如果适用于一个父类,那么一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类的对象能替换父类的对象,而程序逻辑不变。   根据这个理解,隐身含义为:子类可以扩展父类的功能,但不能改变父类原有的功能。
向着百万年薪努力的小赵
2022/12/02
3560
软件架构设计原则--里氏替换原则
面向对象的设计原则-"里氏替换原则"
why(目的):为什么要学习"里式替换原则",我们都知道面向对象的三大特性:封装、继承、多态,该原则就是对良好的"继承关系"定义了一些规范,通过学习理解后可以写出更健壮、更具扩展性的程序;
别明天就今天吧
2020/09/08
8770
可能是最好的设计模式入门教程——里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计(OOD)中比较重要、常见的一种,下面来总结里氏替换原则的知识点,包括:
JavaEdge
2020/05/27
1.5K0
可能是最好的设计模式入门教程——里氏替换原则
软件设计原则讲解,昭昭在目!
大家好,我是小菜,一个渴望在互联网行业做到蔡不菜的小菜。可柔可刚,点赞则柔,白嫖则刚!死鬼~看完记得给我来个三连哦!
蔡不菜丶
2021/01/08
4380
深入理解LSP:里氏替换原则
程序最稳定的状态就是不改变或很少发生改变。模块如果经常发生变化,意味着 这个模块没有很好的分离关注点,做了很多不是自己的事情;单一职责让模块仅有一个变化的原因 也就是只让他负责他关注的事情,不是他关注的事情不负责,
北洋
2023/12/12
2360
设计模式:面向对象的设计原则上(SRP、OCP、LSP)
面向对象的设计原则,我们最熟悉的就是 SOLID 原则,SOLID 原则是五个常用原则的首字母缩写,当然除了 SOLID 原则,还有一些其他的原则,所以后面就分为 SOLID 原则和其他原则两大块来介绍。
oec2003
2021/12/08
5740
设计模式:面向对象的设计原则上(SRP、OCP、LSP)
阿里大佬告诉我,想学习设计模式,得先学好这些硬核技能
可能你不是科班出生,甚至大学都没念,没背景没关系。我们只要每天进步一点点,一个月、两个月、半年、一年......。
田维常
2021/04/22
6250
阿里大佬告诉我,想学习设计模式,得先学好这些硬核技能
JavaScript设计模式经典-面向对象中六大原则
主要学习JavaScript中的六大原则。那么六大原则还记得是什么了吗?六大原则指:单一职责原则(SRP),开放封闭原则(OCP),里氏替换原则(LSP),依赖倒置原则(DIP),接口分离原则(ISP),最少知识原则(LKP)。
达达前端
2019/11/21
8320
JavaScript设计模式经典-面向对象中六大原则
你真的理解 SOLID 面向对象设计原则吗?
一个类只应承担一种责任。换句话说,让一个类只做一件事。如果需要承担更多的工作,那么分解这个类。
用户1093975
2018/12/24
7680
设计模式—–里氏替换原则
开放封闭原则(Open Closed Principle)是构建可维护性和可重用性代码的基础。它强调设计良好的代码可以不通过修改而扩展,新的功能通过添加新的代码来实现,而不需要更改已有的可工作的代码。抽象(Abstraction)和多态(Polymorphism)是实现这一原则的主要机制,而继承(Inheritance)则是实现抽象和多态的主要方法。
对弈
2019/11/09
9480
开工!聊一聊一些设计原则!
大家好,我是光城,很久没发文章了,主要是工作上比较忙,希望大家理解,期待大家留言区交流,本节分享SOLID原则与抽象三原则。
公众号guangcity
2021/11/17
2490
设计模式-里氏替换原则
在上面的三块代码中,当调用SmartTest类的resize方法的时候,如果传入的是父类,那么将会可以的,如果传入的是子类,正方形,那么将会不可以的。
mySoul
2018/11/19
5030
设计模式六大原则(二)----里式替换原则
设计模式原则 之 里氏替换原则(LSP) 有多少小伙伴是不知道里式替换原则的? 我们写了好多年的代码, 天天都在用继承, 子类. 可是, 却不知道里式替换原则? 赶紧来看看吧. 一. 什么是里式替
用户7798898
2021/06/01
10.4K0
设计模式六大原则(二)----里式替换原则
相关推荐
OOAD之设计原则
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验