当前位置: 首页 > news >正文

设计模式—里氏替换原则

1.概念

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

通俗的讲:

1.所有引用基类的地方必须能透明的使用其子类的对象。其父类可以替换成子类,而子类不能替换成父类;

2.子类可以扩展父类的功能,但不能改变父类原有的功能;

2.举例

例如:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”,明显不符合预期,类图如下:

未遵守里氏替换原则:

 
package com.example.demo.principle;public class LSPtest {public static void main(String[] args) {Bird bird1 = new Swallow();Bird bird2 = new BrownKiwi();bird1.setSpeed(120);bird2.setSpeed(120);System.out.println("如果飞行300公里:");try {System.out.println("燕子将飞行" + bird1.getFlyTime(300) + "小时.");System.out.println("几维鸟将飞行" + bird2.getFlyTime(300) + "小时。");} catch (Exception err) {System.out.println("发生错误了!");}}
}//鸟类
class Bird {double flySpeed;public void setSpeed(double speed) {flySpeed = speed;}public double getFlyTime(double distance) {return (distance / flySpeed);}
}//燕子类
class Swallow extends Bird {
}//几维鸟类
class BrownKiwi extends Bird {public void setSpeed(double speed) {flySpeed = 0;}}------------------   运行结果   --------------------------如果飞行300公里:
燕子将飞行2.5小时.
几维鸟将飞行Infinity小时。Process finished with exit code 0

这个设计存在的问题:

  • 几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。

  • 燕子和几维鸟都是鸟类,但是父类抽取的共性有问题,几维鸟的的飞行不是正常鸟类的功能,需要特殊处理,应该抽取更加共性的功能。

遵守里氏替换原则

优化:

取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。

package com.example.demo.principle;public class Lsptest2 {public static void main(String[] args) {Animal animal1 = new Bird();Animal animal2 = new BrownKiwi();animal1.setRunSpeed(120);animal2.setRunSpeed(180);System.out.println("如果奔跑300公里:");try {System.out.println("鸟类将奔跑" + animal1.getRunSpeed(300) + "小时.");System.out.println("几维鸟将奔跑" + animal2.getRunSpeed(300) + "小时。");Bird bird = new Swallow();bird.setFlySpeed(150);System.out.println("如果飞行300公里:");System.out.println("燕子将飞行" + bird.getFlyTime(300) + "小时.");} catch (Exception err) {System.out.println("发生错误了!");}}
}/*** 动物类,抽象的功能更加具有共性*/class  Animal{Double runSpeed;public void setRunSpeed(double runSpeed) {this.runSpeed = runSpeed;}public double getRunSpeed(double distince) {return distince/runSpeed;}}/*** 鸟类继承动物类*/class Bird extends Animal{double flySpeed;public void setFlySpeed(double flySpeed) {this.flySpeed = flySpeed;}public double getFlyTime(double distince) {return distince/flySpeed;}}/*** 几维鸟继承动物类*/class  BrownKiwi extends  Animal{}/*** 燕子继承鸟类  飞行属于燕子的特性,*/class Swallow extends  Bird{}---------   运行结果  -----------------
如果奔跑300公里:
鸟类将奔跑2.5小时.
几维鸟将奔跑1.6666666666666667小时。
如果飞行300公里:
燕子将飞行2.0小时.

3.优点

  • 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;

  • 提高代码的重用性;

  • 提高代码的可扩展性;

  • 提高产品或项目的开放性;

4.缺点

  • 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;

  • 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;

  • 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果————大段的代码需要重构。

相关文章:

设计模式—里氏替换原则

1.概念 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影…...

PyTorch包

进入PyTorch的官网: pytorch GitHub 点击GitHub: 进入PyTorch的主目录: 进入Vision reference: detection: 这就是我们在训练过程中会使用到的文件了:...

22、什么是中间件和权限拦截中间件实操

新建中间件 middleware\auth.js // 定义权限判断中间件,中间件的第一个参数是context export default ({store, redirect}) > {console.log("中间件被调用")// if (!store || !store.state.userinfo) {// redirect("/")// } }页面使用…...

vue.config.js

proxy代理 proxy选项用于配置开发服务器的代理。下面是proxy的全部属性: 1. target (String | Object | Function): 指定要代理的目标主机的URL。可以是一个字符串,也可以是一个对象或函数,用于动态返回目标URL。 2. forward (Boolean): 控…...

80C51单片机----数据传送类指令

目录 一.一般传送指令,即mov指令 1.16位传送(仅1条) 2.8位传送 (1)目的字节为A(累加器) (2)目的字节为Rn(工作寄存器) (3)目的字节为direct…...

【Golang】使用泛型对数组进行去重

背景: 要求写一个方法,返回去重后的数组。数组的类型可能是int64,也可能是string,或是其他类型。 如果区分类型的话,每增加一个新的类型都需要重新写一个方法。 示例代码: //对int64数组进行去重 func DeD…...

Ps:画笔工具的基本操作

画笔工具 Brush Tool是 Ps 中最常用的工具,广泛地用于绘画与修饰工作。 虽然多数操作可在画笔工具的工具选项栏中选择执行,但是如果能记住相应的快捷键可大大提高工作效率。 熟练掌握画笔工具的操作对于使用其他工具也非常有益,因为 Ps 中许多…...

【Apache Doris】一键实现万表MySQL整库同步 | 快速体验

【Apache Doris】一键实现万表MySQL整库同步 | 快速体验) 一、 环境信息1.1 硬件信息1.2 软件信息 二、 流程介绍三、 前提概要3.1 安装部署3.2 JAR包准备3.2.1 数据源3.2.2 目标源 3.3 脚本模版 四、快速体验五、常见问题5.1 Mysql通信异常5.2 MySQL无Key同步异常5…...

35.逻辑运算符

目录 一.什么是逻辑运算符 二.C语言中的逻辑运算符 三.逻辑表达式 三.视频教程 一.什么是逻辑运算符 同时对俩个或者俩个以上的表达式进行判断的运算符叫做逻辑运算符。 举例:比如去网吧上网,只有年满十八周岁并且带身份证才可以上网。在C语言中如果…...

ASP.NET Core 启用CORS

浏览器的安全阻止一个域的本地页面请求另外不同域的本地页面,这个限制叫同源策略,这个安全特性用来阻止恶意站点从别的网站读取数据 例如假如我有一个页面叫A.html https://foo.example/A.html 现在页面A.html有一个ajax代码尝试读取B.html的HTML的源…...

io.lettuce.core.RedisCommandExecutionException

io.lettuce.core.RedisCommandExecutionException: ERR invalid password ERR invalid password-CSDN博客 io.lettuce.core.RedisCommandExecutionException /** Copyright 2011-2022 the original author or authors.** Licensed under the Apache License, Version 2.0 (the…...

vue3 导出数据为 excel 文件

文章目录 安装插件封装组件 -- Export2Excel.js多表封装界面使用 -- 数据处理成二维数组更多 菜鸟最近做了一个需求,就是需要上传表单并识别,然后识别出来的内容要可以修改,然后想的就是识别内容变成 form 表单,所以并没有使用 Sp…...

PyQt6简介

锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计12条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话版…...

某60区块链安全之未初始化的存储指针实战二学习记录

系列文章目录 文章目录 系列文章目录未初始化的存储指针实战二实验目的实验环境实验工具实验原理实验内容实验过程EXP利用 未初始化的存储指针实战二 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约未初始化的存储指针漏洞 找到合约漏洞进行分析并形成利用 实验…...

软件工程第十二周

软件作坊、软件危机、软件过程控制、重型控制、敏捷、DevOps 这些术语概括了软件开发历史和实践中的几个重要概念和阶段。让我们逐一解析它们: 软件作坊(Software Craftsmanship):这是软件开发的早期模式,强调个人技能…...

electron 问题记录

23年11月24 electron项目npm install 卡在一个地方不动 原因:主要是 install electron 会卡住 解决方法: # 先解决install electron卡死 npm install -g cnpm --registryhttps://registry.npmmirror.com cnpm install electron# 然后下载其他依赖 np…...

nodejs+vue+python+PHP+微信小程序-留学信息查询系统的设计与实现-安卓-计算机毕业设计

1、用户模块: 1)登录:用户注册登录账号。 2)留学查询模块:查询学校的入学申请条件、申请日期、政策变动等。 3)院校排名:查询国外各院校的实力排名。 4)测试功能:通过入学…...

JWT和Token之间的区别

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:每天一个知识点 ✨特色专栏&#xff1a…...

UserRole

Qt::UserRole 是 Qt::ItemDataRole 枚举中的一个成员,用于表示自定义数据角色(Data Role)的起始值。 在 Qt 中,Qt::ItemDataRole 枚举用于标识项(Item)中不同类型的数据。这些数据角色包括 Qt::DisplayRol…...

java学习part10 this

90-面向对象(进阶)-关键字this调用属性、方法、构造器_哔哩哔哩_bilibili 1.java的this java的this性质类似cpp的this, 但它是一种引用,所以用 this. xxx来调用。 this代表当前的类的实例,所以必须和某个对象结合起来使用,不能…...

AI-MVP:以最小模型验证最大价值,聚焦AI智能体研究

MVP(Minimum Viable Product,最小可行产品)是一种产品开发方法论,指用最低成本、最快速度构建出具备核心功能、足以验证基本商业假设的产品初始版本。 其核心目的是通过收集早期用户反馈来验证市场需求,从而指导后续迭…...

智能手机传感器数据建模与人类活动识别技术解析

1. 智能手机数据建模人类活动的核心价值每天早上7点15分,我的手机都会自动关闭飞行模式——这不是什么魔法,而是基于我过去三个月起床时间的机器学习模型在起作用。通过分析手机传感器数据来识别人类活动模式,这种技术正在彻底改变我们与移动…...

别再手动建模了!3DMAX 2011+ 用户必看:这个螺母螺栓插件,5分钟搞定标准件

3DMAX高效建模革命:参数化螺母螺栓插件深度解析 在机械设计与工业产品建模领域,标准件的重复创建一直是设计师的痛点。传统手动建模一颗符合国标的六角螺母,熟练设计师至少需要15分钟调整参数和检查尺寸,而一个中等复杂度的装配体…...

PyTorch训练循环中zero_grad()的正确调用位置详解

在PyTorch中,optimizer.zero_grad()必须在loss.backward()之前执行,且绝不能位于backward()与step()之间;其具体位置(循环开头或backward()前一刻)不影响梯度计算逻辑,但影响代码可读性与多优化器场景下的正…...

《JAVA面经实录》- 权限管理框面试题

《JAVA面经实录》- 权限管理框面试题Java权限管理框架面试题(23道高频题)本文严格按照指定题目顺序,整理每道题的面试标准回答补充要点,贴合后端面试实战场景,语言简洁、重点突出,可直接用于备考&#xff0…...

生成式AI如何革新汽车软件测试?

1. 汽车行业软件测试的范式转变在传统汽车制造时代,机械性能是核心竞争力,而今天这个指标已经变成了"代码行数"。现代高端智能汽车的代码量已突破1亿行,是波音787客机的16倍。这种软件爆炸式增长带来了一个关键痛点:如何…...

告别Keil/IAR:用Ozone+J-Trace调试STM32F407,这些隐藏功能真香了

从Keil到Ozone:STM32F407VG调试效率的全面升级 调试嵌入式系统时,传统IDE如Keil和IAR已经无法满足现代开发对效率和深度的需求。当我第一次尝试将STM32F407VG项目迁移到OzoneJ-Trace组合时,那种"降维打击"般的调试体验彻底改变了我…...

Openclaw 高效数据采集实战指南

① 多源异构网站数据抓取场景解析 在实际的数据采集工作中,我们最常遇到的挑战并非技术本身的复杂度,而是目标源的“千奇百怪”。所谓的“多源异构”,简单来说就是你要抓的网站长得都不一样:有的还是十年前的老式 HTML 静态页&…...

Brain | 大脑的“隐秘连接”:神经可塑性的连接组储备?

摘要本文提出了一个与神经可塑性和认知储备相关的新概念:连接组储备(Connectomic reserve)。该概念旨在推动实验验证,并以胼胝体神经元及其投射在发育过程中所形成的冗余神经环路为例加以阐释。通过回顾胼胝体环路的形成机制——从皮层神经元胞体发出轴突…...

别再傻傻撞库了!手把手教你用Python脚本批量破解MD5弱密码(附实战代码)

从零构建自动化MD5弱密码碰撞系统:红队实战指南 密码安全一直是网络安全攻防中的核心战场。当企业数据库遭遇泄露时,攻击者首先瞄准的往往是那些采用简单哈希算法保护的密码字段。作为安全从业者,我们有必要深入了解攻击者的常用手段——特别…...