后端技术面试 38 讲
李智慧
同程艺龙交通首席架构师,前 Intel& 阿里架构师,《大型网站技术架构》作者
37373 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
不定期加餐 (1讲)
后端技术面试 38 讲
15
15
1.0x
00:00/00:00
登录|注册

13丨软件设计的里氏替换原则:正方形可以继承长方形吗?

子类override的异常
对象适配器模式
组合优于继承
继承设计的注意事项
JDK中的例子
子类的契约不能比父类更严格
类的公有方法是契约
测试面积的例子
实现方式
使用“IS A”进行判断
修改drawShape方法
在基类Shape中定义draw方法
drawShape方法
继承的合理性需要放在应用场景中判断
子类型能替换基类型
如何进行对象的设计
将属性和方法封装在类里
利用多态的特性
不需要直接耦合
运行期绑定具体类
面向接口进行编程
多态
继承
封装
里氏替换原则说明
父类抽象方法的异常
小结
子类不能比父类更严格
使用场景
正方形类设计
判断继承是否合理
问题解决
代码示例
里氏替换原则
封装的关键
设计模式和多态
多态的作用
面向对象编程语言的特性
思考题
正方形可以继承长方形吗?
一个违反里氏替换规则的例子
介绍
软件设计的里氏替换原则

该思维导图由 AI 生成,仅供参考

我们都知道,面向对象编程语言有三大特性:封装、继承、多态。这几个特性也许可以很快就学会,但是如果想要用好,可能要花非常多的时间。
通俗地说,接口(抽象类)的多个实现就是多态。多态可以让程序在编程时面向接口进行编程,在运行期绑定具体类,从而使得类之间不需要直接耦合,就可以关联组合,构成一个更强大的整体对外服务。绝大多数设计模式其实都是利用多态的特性玩的把戏,前面两篇学习的开闭原则和依赖倒置原则也是利用多态的特性。正是多态使得编程有时候像变魔术,如果能用好多态,可以说掌握了大多数的面向对象编程技巧。
封装是面向对象语言提供的特性,将属性和方法封装在类里面。用好封装的关键是,知道应该将哪些属性和方法封装在某个类里。一个方法应该封装进 A 类里,还是 B 类里?这个问题其实就是如何进行对象的设计。深入研究进去,里面也有大量的学问。
继承似乎比多态和封装要简单一些,但实践中,继承的误用也很常见。

里氏替换原则

关于如何设计类的继承关系,怎样使继承不违反开闭原则,实际上有一个关于继承的设计原则,叫里氏替换原则。这个原则说:若对每个类型 T1 的对象 o1,都存在一个类型 T2 的对象 o2,使得在所有针对 T2 编写的程序 P 中,用 o1 替换 o2 后,程序 P 的行为功能不变,则 T1 是 T2 的子类型。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

软件设计中的里氏替换原则是面向对象编程中的重要设计原则之一。该原则要求子类能够替换其父类并且不影响程序的功能。本文通过讨论多态、封装和继承的关系,以及里氏替换原则的具体应用和违反情况,深入解释了里氏替换原则的重要性和实际应用。文章还通过具体例子,如马的继承设计和正方形继承长方形的情况,帮助读者理解了里氏替换原则在实际开发中的应用。通过这些例子,读者可以更好地理解里氏替换原则,并在实际开发中避免违反该原则。文章最后提出了解决违反里氏替换原则的方法,为读者提供了实用的建议。通过本文的阐述,读者可以更好地理解和应用里氏替换原则,提高软件设计的质量和可维护性。文章还强调了在实践中,继承一个父类仅仅是为了复用父类中的方法时,很可能会违反里氏替换原则,建议使用组合而非继承。最后,文章留下了一个思考题,引发读者对里氏替换原则的深入思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端技术面试 38 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(35)

  • 最新
  • 精选
  • 俊杰
    BException应该是AException的子类,否则当使用子类替换父类后,抛出的BException无法被catch(AException e)语句捕获

    作者回复: √

    2019-12-20
    44
  • yang
    满满的干货 子类不能抛出比父类无法catch的异常-因此应该要是AException子类 现实开发中往往经常看到,不同的子类实现了不同的具体方法,而父类只是一个抽象方法。 在方法入口处传入用父类作为形参来接受参数,而在其中又调用父类.abstractMethod(); class abstracr A{ void abstract f(); } class X extneds A { void f(){ pribt("x"); } } class Y extends A { void f(){ print("y"); } } // test(A a); void test(A a){ a.f(); } 老师,这个test(A a); 的使用 ,或者这两个类 X Y, 有违反里氏替换原则吗? (手机输入的)

    作者回复: 不违法,抽象方法的正确用法。

    2020-01-18
    2
  • 靠人品去赢
    老师你看一下,能不能长方形继承正方形,既然正向不行,那就反向操作。 正方形作为父类,它更严格,长方形作为继承,正方形获取边长getLong(),长方形是getLong(String type)。

    作者回复: 亲,不建议继承具体类呢,优先考虑组合而不是继承具体类~

    2019-12-23
    5
    2
  • pinteressante
    这个概念从理解上来说还是比较混沌和违反直觉的. 子类这里的子从字面上理解就是小, 又很容易联想到子集的概念,而一个集合的子集是小于等于自己的. 那么里氏替换原则讲到可以用"子类不能比父类更严格"就会让人在理解上产生困惑: 1. 如果可以替换我干嘛要用子类呢?换句话说,如果只是同级别的类干嘛要产生父子关系,直接定义不就好了?或者说,定义了一些类,抽取他们的共性变成父类,这不就又成了里氏替换原则的反例了么? 2. 如果我目的就是为了缩小范围而不是扩大范围或者范围不变,我定义子类难道还"犯错了"吗? 3. 常见的场景是什么呢?

    作者回复: 继承的关键词是extends,就是“扩展”的意思。

    2021-02-22
    1
  • Peter
    在类的继承中,如果父类方法的访问控制是 protected,那么子类 override 这个方法的时候,可以改成是 public,但是不能改成 private。因为 private 的访问控制比 protected 更严格,能使用父类 protected 方法的地方,不能用子类的 private 方法替换,否则就是违反里氏替换原则的。 想问下,这个针对protected继承或者private继承也适用的吗?

    作者回复: protected 是的。 PS:private方法子类不可见,也就不存在override。

    2021-06-19
  • 雨天
    老师,请教两个问题 1.里氏替换原则是关注程序能正常运行,还是系统的逻辑不变(行为功能不变);如果只是程序能正常运行的话,基本上可以说里氏替换原则很难被违反;毕竟基类能被调用的方法,子类一定有;但是如果逻辑不变的话,则子类不能重写父类的非抽象方法? 2.void drawShape(Shape shape) { shape.draw();}中如果用Square直接替换Shape肯定也是不行的;这样的话,就不能接受Circle,即没有多态;这是不是和里式替换有点矛盾?

    作者回复: 1 违反原则很可能意味着你的程序设计不良(也不是绝对),而不是不能运行。 2 子类替换父类是用来验证继承设计是否良好,不是真的要把代码中的父类替换了。。。没有意义啊。。。

    2021-02-25
    2
  • BIZ_DATA_3
    "这两个类都是从 JDK1 就已经存在的,我想,如果能够重新再来,JDK 的工程师一定不会这样设计。这也从另一个方面说明,不恰当的继承是很容易就发生的,设计继承的时候,需要更严谨的审视。" 李老师能否能够给一些更合理的设计,这样更容易让读者理解

    作者回复: 小结里讲了,使用适配器模式,用组合而不是继承

    2020-11-06
  • 第一装甲集群司令克莱斯特
    栈stack的数据存储特点是FILO,先进后出吧。

    作者回复: 笔误,谢谢指正~

    2020-02-01
    3
  • 里氏替换原则 要求子类可以无缝的替换父类,比父类更松。 但是在实际的开发中,往往是子类比父类更加严格,细化到适合使用在某一应用场景下,目的性越来越明确 父类的设计只是一个比较宽松的限制,子类继承然后重写在某一具体场景下的逻辑
    2019-12-21
    7
    15
  • 不记年
    子类 根据里氏变换,父类比子类更严格 => 子类的方法严格性小于父类的 => AException 严格性 大于 BException => AException 是 BException的父类
    2020-02-01
    6
收起评论
显示
设置
留言
35
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部