软件设计之美
郑晔
开源项目 Moco 作者
19890 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
软件设计之美
15
15
1.0x
00:00/00:00
登录|注册

22 | Liskov替换原则:用了继承,子类就设计对了吗?

你好!我是郑晔。
上一讲,我们讲了开放封闭原则,想要让系统符合开放封闭原则,最重要的就是我们要构建起相应的扩展模型,所以,我们要面向接口编程。
而大部分的面向接口编程要依赖于继承实现,虽然我们在前面的课程中说过,继承的重要性不如封装和多态,但在大部分面向对象程序设计语言中,继承却是构建一个对象体系的重要组成部分。
理论上,在定义了接口之后,我们就可以把继承这个接口的类完美地嵌入到我们设计好的体系之中。然而,用了继承,子类就一定设计对了吗?事情可能并没有这么简单。
新的类虽然在语法上声明了一个接口,形成了一个继承关系,但我们要想让这个子类真正地扮演起这个接口的角色,还需要有一个好的继承指导原则。
所以,这一讲,我们就来看看可以把继承体系设计好的设计原则:Liskov 替换法则。

Liskov 替换原则

2008 年,图灵奖授予 Barbara Liskov,表彰她在程序设计语言和系统设计方法方面的卓越工作。她在设计领域影响最深远的就是以她名字命名的 Liskov 替换原则(Liskov substitution principle,简称 LSP)。
1988 年,Barbara Liskov 在描述如何定义子类型时写下这样一段话:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Liskov替换原则(LSP)是面向对象设计中的重要原则之一,要求子类型必须能够替换其父类型,以确保程序行为的一致性。本文深入探讨了LSP的定义、重要性和应用。通过实例分析展示了LSP的应用,指出了一些常见的违反LSP的问题,如运行时类型识别和继承数据结构。文章还讨论了基于行为的IS-A关系,强调了IS-A关系的判定是基于行为的,只有行为相同才能满足IS-A关系。此外,文章还探讨了LSP在更广泛的接口设计中的应用,强调了公开接口的宝贵性和需要精心考量。通过对LSP原则的深入讨论,读者可以更好地理解和应用该原则,从而改善面向对象设计的质量。文章以引发读者思考的方式结束,鼓励读者思考并提出解决问题的方案。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《软件设计之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(31)

  • 最新
  • 精选
  • zcc
    那从父类的角度来考虑的话,应该是定义一个几何图形的接口,接口有计算面积的方法。然后长方形、正方形、圆形、三角形……都实现这个接口,然后各自实现计算面积的方法。各自有自己特别的关键属性,根据属性计算各自面积:长*宽、边长²、πr²、(底长*高)/2、……

    作者回复: 嗯,这个解决方案的味道不错。

    2020-07-17
    21
  • Janenesome
    千万要遏制自己写 if 的念头,一旦开了这个头,后续的代码也将变得难以维护。刚好前段时间看到过一种说法:以多态应用为荣,以分支判断为耻。哈哈

    作者回复: 这个观点真好!

    2020-10-23
    18
  • Geek_3b1096
    时刻提醒自己: 千万要遏制写if的念头

    作者回复: 非常好的经验总结!

    2020-08-09
    11
  • 桃子-夏勇杰
    这个设计原则看着非常简单,提出者居然能获得图灵奖,可见这个设计原则的价值非常大。郑老师,这个设计原则的价值到底有多大呢?

    作者回复: LSP告诉我们什么样的继承是对的,而继承使用范围太广了。

    2020-07-29
    6
  • Janenesome
    郑老师给出的业务开发的案例真的挺接地气。 运行时类型识别我以前写过,后面回去维护的时候想打死自己,怎么写出这样的烂代码。 还有业务分析里的素材分类,太真实了,平时做需求时很多概念有点相似,放在一起好像也可以而且看起来还能省点力气,没有太深入思考的话就会放在一起了,一些差异化的部分就单独存或者用条件判断。

    作者回复: 今天“偷懒”,明天要付出更多。

    2020-10-23
    2
    4
  • monalisali
    RequestParser 中还是免不了用多个 if 来判断 identifier,从而返回特定的子类吧

    作者回复: 不一定,可以通过一个Map实现。

    2020-07-20
    5
    4
  • Being
    全篇一直在强调行为,我想这也是思考题的突破口。长宽是数据,而Rectangle并没有将行为抽象出来,导致Rectangle和Square不能成为IS-A的关系,我们只要把求面积的行为放在Rectangle下,子类分别去实现面积的方法就好了。

    作者回复: “把求面积的行为放在Rectangle下,子类分别去实现面积的方法”,可以解决这个问题吗?

    2020-07-18
    2
    4
  • 呆呆狗的兽
    lsp这一分享,很精髓也很精彩,is-a这个太重要了,遵循is-a会让系统越来越稳定且易拓展

    作者回复: 嗯,这个是关键的。

    2021-07-19
    2
  • Jxin
    如果业务场景合适,约束功能也不失为一个解决办法。让宽高不可变,初始化时就必须赋值。这样就能符合现实中的特性。自然也没有长宽赋不同值的麻烦。

    作者回复: setter 确实是一个有杀伤力的东西,但回避 setter并不是在解决我们提出的问题。

    2020-07-17
    2
  • BBQ
    关于不同客户的不同格式问题,我们单独开发了一套系统,在这个系统里面做接口格式映射,然后再调用标准接口。 由于这个系统的受众是实施人员,所以界面做到可以通过拖拽来实现映射。 当然实际功能更多,包括聚合,转换,以及enrich 功能 总之,把这个映射的关注点单独独立成了一个系统。

    作者回复: 如果有特定的需求,这么做是没有问题的

    2021-07-04
    1
收起评论
显示
设置
留言
31
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部