设计原则之里氏替换原则详解

设计原则之里氏替换原则详解一 里氏替换原则定义定义 如果对每一个类型为 T1 的对象 O1 都有类型为 T2 的对象 O2 使得所有以 T1 定义的所有程序 P 在所有的对象 O1 都替换成 O2 时 程序 P 的行为没有发生任何变化 那么类型 T2 是类型 T1 的子类型 通俗理解就是 子类可以扩展父类的功能 但不能改变父类原有的功能 有以下几个引申含义 子类可以实现父类的抽象方法 但不能覆盖父类的非抽象方法 子类中可以增加自己特有的方法 当子类的方法重载父类的方法时 方法的前置条件 方法的输入 入参 要比父类的入参更宽松 当子类的方法实现父类的方法时

一、里氏替换原则定义

定义: 如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得所有以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生任何变化,那么类型T2是类型T1的子类型。

通俗理解就是:子类可以扩展父类的功能,但不能改变父类原有的功能。有以下几个引申含义:
  1. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  2. 子类中可以增加自己特有的方法。
  3. 当子类的方法重载父类的方法时,方法的前置条件(方法的输入,入参)要比父类的入参更宽松。
  4. 当子类的方法实现父类的方法时(重写,重载,实现抽象方法),方法的后置条件(输出、返回值)要比父类更严格或相等。
概念扩展:一个软件实体如果适用一个父类的话,那么一定适用其子类,所有引用父类的地方必须能透明的使用其子类的对象,子类对象能够替换其父类对象,而程序的逻辑不变。
里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,它反映了基类与子类之间的关系,是对开闭原则的补充。

二、里氏替换原则优点

  1. 约束继承泛滥,它也是开闭原则的一种很好的体现。
  2. 提高了代码的重用性。
  3. 降低了系统的出错率。类的扩展不会给原类造成影响,降低了代码出错的范围和系统出错的概率。
  4. 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。

三、下面我们举符合和不符合的里氏替换原则的例子说明

例子描述: 先定义一个长方形类,正方形是特殊的长方形,再定义一个正方形类继承长方形类并重写长方形类中的方法,再编写一个测试类,测试类中定义一个方法,当长方形的长度大于宽度时候,高度每次加一,输出长和宽的数值。在main方法中给长方形长和宽赋初始值。发现长方形打印没问题。但如果给main方法中的正方形边长赋值,则while条件会变成永真条件,无限输出,这就违背了里氏替换原则,因为用父类执行可以,用子类执行逻辑就被改变了。

@Getter @Setter public class Rectangle { 
   //长方形 private long height; private long width; } @Setter @Getter public class Square extends Rectangle{ 
   //正方形 private long length; @Override public long getHeight() { 
    return getLength(); } @Override public long getWidth() { 
    return getLength(); } @Override public void setHeight(long height) { 
    setLength(height); } @Override public void setWidth(long width) { 
    setLength(width); } } public class SimpleTest { 
    public static void resize(Rectangle rectangle) { 
    while (rectangle.getWidth() >= rectangle.getHeight()){ 
    rectangle.setHeight(rectangle.getHeight() +1); System.out.println("width:" + rectangle.getWidth()+",height:"+rectangle.getHeight()); } } public static void main(String[] args) { 
    Rectangle rectangle = new Rectangle(); rectangle.setWidth(10); rectangle.setHeight(5); resize(rectangle); Square square = new Square(); square.setLength(10); resize(square); } } 

我们怎么修改代码使它遵循里氏替换原则呢,我们可以抽象出来一个四边形接口,长方形和正方形分别实现接口。

@Getter @Setter public class Rectangle implements QuadRangle{ 
   //长方形 private long height; private long width; } public interface QuadRangle { 
   //四边形接口 long getWidth(); long getHeight(); } @Setter @Getter public class Square implements QuadRangle{ 
   //正方形 private long length; @Override public long getWidth() { 
    return length; } @Override public long getHeight() { 
    return length; } } public class SimpleTest { 
    public static void resize(Rectangle rectangle) { 
    while (rectangle.getWidth() >= rectangle.getHeight()){ 
    rectangle.setHeight(rectangle.getHeight() +1); System.out.println("width:" + rectangle.getWidth()+",height:"+rectangle.getHeight()); } System.out.println("Resize End,width:" + rectangle.getWidth()+",height:"+rectangle.getHeight()); } public static void main(String[] args) { 
    Rectangle rectangle = new Rectangle(); rectangle.setWidth(10); rectangle.setHeight(5); resize(rectangle); Square square = new Square(); square.setLength(10); resize(square); } } 

然后这里的 Rectangle参数就不能被改变了,如果传入QuadRangle则会报错,避免了继承泛滥问题

public static void resize(Rectangle rectangle) { 
    

正方形也无法调用resize方法,不满足条件,这就通过修改符合了里氏替换原则。

resize(square); 

这也只是类的继承关系结构之间的里氏替换原则的体现。方法上的里氏替换原则的具体体现就不再演示了。日常中大家也一直在使用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214197.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午4:46
下一篇 2026年3月18日 下午4:46


相关推荐

  • pycharm激活码 2021 3月最新注册码

    pycharm激活码 2021 3月最新注册码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    74
  • 1/7的小数点后2020位的数字是_九八K

    1/7的小数点后2020位的数字是_九八K给定长度为 N 的整数序列 A,下标为 1∼N。现在要执行 M 次操作,其中第 i 次操作为给出三个整数 li,ri,ki,求 A[li],A[li+1],…,A[ri] (即 A 的下标区间 [li,ri])中第 ki 小的数是多少。输入格式第一行包含两个整数 N 和 M。第二行包含 N 个整数,表示整数序列 A。接下来 M 行,每行包含三个整数 li,ri,ki,用以描述第 i 次操作。输出格式对于每次操作输出一个结果,表示在该次操作中,第 k 小的数的数值。每个结果占一行。数据范围

    2022年8月9日
    14
  • 单片机交通信号灯控制系统设计_交通灯控制电路设计图

    单片机交通信号灯控制系统设计_交通灯控制电路设计图交通信号灯控制系统设计 作为一个硬件程序设计民工,最近一直在学习python,写个爬虫,排个序,再画个界面,其实还是挺好玩的。然而这不是我的主业啊!!!-_-|||下学期开学就要找工作了,明天刚好是新的一个月,还是滚回去调我的FPGA吧。今天先更新一个很小很小的例子作为开端,这是前几天xxx给我出的一道很随意的题目,主要是看面对一个项目…

    2026年3月7日
    4
  • css怎么改鼠标样式,如何利用CSS改变鼠标的样式

    css怎么改鼠标样式,如何利用CSS改变鼠标的样式各种各样的鼠标样式,对于经常使用电脑的人而言一定不会生疏。当鼠标移动到不同的地方时,当鼠标执行不同的功能时,鼠标的外形都会发生变化。但在网页上,貌似只有当鼠标在超级链接上时才出现一个手形,在其它地方似乎没有什么变化,同布满动感的网页显得不怎么和谐。实际上,用css可以方便地定义许多种鼠标外形。下面小编就为大家介绍一下怎样利用CSS改变鼠标的样式。用CSS改变鼠标的样式,我们使用cursor属性,现…

    2022年5月31日
    39
  • logistic回归详解一:为什么要使用logistic函数

    logistic回归详解一:为什么要使用logistic函数从线性分类器谈起 给定一些数据集合 他们分别属于两个不同的类别 例如对于广告数据来说 是典型的二分类问题 一般将被点击的数据称为正样本 没被点击的数据称为负样本 现在我们要找到一个线性分类器 将这些数据分为两类 当然实际情况中 广告数据特别复杂 不可能用一个线性分类器区分 用 X 表示样本数据 Y 表示样本类别 例如 1 与 1 或者 1 与 0 我们线性分类器的目的 就是找到一个超平面 Hyperplan

    2026年3月20日
    2
  • idea2021.11.3永久激活【2021免费激活】

    (idea2021.11.3永久激活)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月29日
    79

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号