当前位置: 首页 > 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代表当前的类的实例,所以必须和某个对象结合起来使用,不能…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...