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

软件设计原则-里氏替换原则讲解以及代码示例

里氏替换原则

一,介绍

1.前言

里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一条重要原则,它由Barbara Liskov在1987年提出。

里氏替换原则的核心思想是:父类的对象可以被子类的对象替换,而程序的行为不会发生变化。也就是说,如果一个类型A是另一个类型B的子类型,那么在任何使用B的地方都可以使用A,而不会引起错误或异常。

2.何时使用里氏替换原则

  1. 当需要编写基类或抽象类时:在编写基类或抽象类时应该尽可能地遵循里氏替换原则,以保证后续的子类能够正确地继承和使用基类的接口或者抽象类的方法。

  2. 当需要对已有的代码进行重构时:在重构已有的代码时,我们可以通过遵循里氏替换原则,使得代码更加易于理解、扩展和维护。通过将某些动态绑定的行为转化为静态绑定的行为,可以降低代码的复杂度并增强其可控性。

  3. 当需要进行单元测试或集成测试时:在进行单元测试或集成测试时,我们可以使用子类对象来替换父类对象,以确保测试结果的准确性。如果使用子类对象无法替换相应的父类对象,则表示可能存在设计上的问题,需要进一步优化。

  4. 当需要扩展系统的功能时:在扩展系统的功能时,我们应该尽可能地遵循里氏替换原则,以确保新的组件能够与现有的组件正常协作。通过使用基类或抽象类来定义接口,可以使得组件之间的耦合度更低。

二,代码示例

为了更详细地介绍里氏替换原则,我们可以通过一个例子来说明:

假设有一个图形计算程序,程序可以计算不同形状图形的面积。最初的设计可能会像这样:

class Shape {// 省略其他属性和方法public double calculateArea() {// 默认实现,返回0return 0;}
}class Rectangle extends Shape {private double width;private double height;// 省略构造方法和其他属性方法@Overridepublic double calculateArea() {return width * height;}
}class Circle extends Shape {private double radius;// 省略构造方法和其他属性方法@Overridepublic double calculateArea() {return Math.PI * radius * radius;}
}


这个设计看起来似乎没有问题,但问题在于当我们需要添加新的图形类型时,比如三角形,计算面积的方式与矩形和圆形不同,会导致父类的默认实现无法满足需求。

为了符合里氏替换原则,我们可以进行重构。首先,我们定义一个抽象类`Shape`:

abstract class Shape {public abstract double calculateArea();
}

然后,对每种具体的图形类型,创建一个子类并实现`calculateArea()`方法:

class Rectangle extends Shape {private double width;private double height;// 省略构造方法和其他属性方法@Overridepublic double calculateArea() {return width * height;}
}class Circle extends Shape {private double radius;// 省略构造方法和其他属性方法@Overridepublic double calculateArea() {return Math.PI * radius * radius;}
}class Triangle extends Shape {private double base;private double height;// 省略构造方法和其他属性方法@Overridepublic double calculateArea() {return 0.5 * base * height;}
}

现在,我们可以通过扩展子类来添加新的图形类型,而且每个子类都提供了自己的面积计算方式。

这个重构后的设计符合里氏替换原则,因为我们可以将子类的对象替换父类的对象,而不影响程序的行为。这样做的好处是,通过面向抽象编程,代码更加灵活、可扩展,同时也提高了系统的可维护性和可测试性。

总结起来,里氏替换原则强调了继承关系的正确使用,要求子类能够完全替代父类,而不破坏程序的正确性。遵循该原则可以提高代码的重用性、灵活性和可靠性,是良好的软件设计实践之一。

三,优缺点

优点:

  1. 提高代码的可复用性:遵循里氏替换原则可以确保子类对象能够替换父类对象,这意味着我们可以使用统一的接口或抽象类来处理一组对象,从而提高了代码的可复用性。

  2. 增强程序的可扩展性:通过良好的继承关系,可以在不修改现有代码的情况下,通过添加新的子类来扩展系统的功能。这样可以降低对原有代码的影响范围,提高了程序的可扩展性。

  3. 促进代码的层次化结构:通过定义好的抽象类或接口,可以将代码按照层次化的结构组织起来,提高代码的可读性和可维护性。

  4. 提高代码的可测试性:遵循里氏替换原则可以使得代码更易于进行单元测试,因为我们可以使用父类对象来代替子类对象进行测试,从而提高了代码的可测试性。

缺点:

  1. 过度约束:有时为了满足里氏替换原则,可能需要引入过多的抽象类或接口,导致代码变得复杂,增加了设计和开发的难度。

  2. 需要在继承关系上建立合适的层次结构:正确地使用里氏替换原则需要在继承关系上建立适当的层次结构,这需要设计者有较强的面向对象设计能力。

  3. 可能违反单一职责原则:为了满足里氏替换原则,有时需要在父类中定义多个不相关的接口或抽象方法,这可能违反了单一职责原则,导致代码的可读性和维护性下降。

总的来说,里氏替换原则通过良好的继承关系可以提高代码的可复用性、可扩展性和可测试性,但需要在继承关系的层次结构上做出合理的设计,并权衡与其他设计原则的关系。

相关文章:

软件设计原则-里氏替换原则讲解以及代码示例

里氏替换原则 一,介绍 1.前言 里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一条重要原则,它由Barbara Liskov在1987年提出。 里氏替换原则的核心思想是:父类的对象可以被子类的…...

Sui提供dApp Kit 助力快速构建React Apps和dApps

近日,Mysten Labs推出了dApp Kit,这是一个全新的解决方案,可用于在Sui上开发React应用程序和去中心化应用程序(dApps)。mysten/dapp-kit是专门为React定制的全新SDK,旨在简化诸如连接钱包、签署交易和从RPC…...

2023年系统设计面试如何破解?进入 FAANG 面试的实战指南

如果您正在准备编码面试,但想知道如何准备关键的系统设计主题,并寻找正确方法、技巧和问题的分步指导,那么您来对地方了。在本文中,我将分享 2023 年系统设计面试的完整指南。 在软件开发领域,如果您正在申请高级工程…...

(react+ts)vite项目中的路径别名的配置

简单两个步骤 找到vite.config.ts,这里会现实报错,需要安装一下 npm i -D types/node 这个库的ts声明配置 import path from path // https://vitejs.dev/config/ export default defineConfig({plugins: [react()],resolve:{alias:{"":path.resolve(__…...

【MATLAB源码-第51期】基于matlab的粒子群算法(PSO)的栅格地图路径规划。

操作环境: MATLAB 2022a 1、算法描述 粒子群算法(Particle Swarm Optimization,简称PSO)是一种模拟鸟群觅食行为的启发式优化方法。以下是其详细描述: 基本思想: 鸟群在寻找食物时,每只鸟都会…...

React之render

一、原理 首先&#xff0c;render函数在react中有两种形式&#xff1a; 在类组件中&#xff0c;指的是render方法&#xff1a; class Foo extends React.Component {render() {return <h1> Foo </h1>;} }在函数组件中&#xff0c;指的是函数组件本身&#xff1a…...

基于springboot实现财务管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现财务管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#x…...

设计模式:组合模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《模板模式》 下一篇《代理模式》 简介&#xff1a; 组合模式&#xff0c;它是一种用于处理树形结构、表示“部分-整体”层次结构的设计模式。它允许你将对象组合成树形结构&#xff0c;以表示部分…...

超强满血不收费的AI绘图教程来了(在线Stable Diffusion一键即用)

超强满血不收费的AI绘图教程来了&#xff08;在线Stable Diffusion一键即用&#xff09; 一、简介1.1 AI绘图1.2 Stable Diffusion1.2.1 原理简述1.2.2 应用流程 二、AI绘图工具2.1 吐司TusiArt2.2 哩布哩布LibLibAI2.3 原生部署 三、一键即用3.1 开箱尝鲜3.2 模型关联3.3 Cont…...

【蓝桥每日一题]-动态规划 (保姆级教程 篇12)#照相排列

这次是动态规划最后一期了&#xff0c;感谢大家一直以来的观看&#xff0c;以后就进入新的篇章了 目录 题目&#xff1a;照相排列 思路&#xff1a; 题目&#xff1a;照相排列 思路&#xff1a; 首先记录状态f[a][b][c][d][e]表示每排如此人数下对应的方案数&#xff0c;然…...

纺织工厂数字孪生3D可视化管理平台,推动纺织产业数字化转型

近年来&#xff0c;我国加快数字化发展战略部署&#xff0c;全面推进制造业数字化转型&#xff0c;促进数字经济与实体经济深度融合。以数字孪生、物联网、云计算、人工智能为代表的数字技术发挥重要作用。聚焦数字孪生智能工厂可视化平台&#xff0c;推动纺织制造业数字化转型…...

【七】SpringBoot为什么可以打成 jar包启动

SpringBoot为什么可以打成 jar包启动 简介&#xff1a;庆幸的是夜跑的习惯一直都在坚持&#xff0c;正如现在坚持写博客一样。最开始刚接触springboot的时候就觉得很神奇&#xff0c;当时也去研究了一番&#xff0c;今晚夜跑又想起来了这茬事&#xff0c;于是想着应该可以记录一…...

031-第三代软件开发-屏幕保护

第三代软件开发-屏幕保护 文章目录 第三代软件开发-屏幕保护项目介绍屏幕保护 关键字&#xff1a; Qt、 Qml、 MediaPlayer、 VideoOutput、 function 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#…...

Ubuntu 22.04 更新完内核重启卡在 grub 命令行解决办法

倒霉伊始 升级内核过程中出现如下警告&#xff0c;然后重启引导失败&#xff1a; Warning: os-prober will not be executed to detect other bootable partitions 屏幕内容如下&#xff1a; GNU GRUB version 2.06Minimal BASH-like line editing is supported. For the fir…...

Stream流式处理

Stream流式处理&#xff1a; 建立在Lambda表达式基础上的多数据处理技术。 可以对集合进行迭代、去重、筛选、排序、聚合等处理&#xff0c;极大的简化了代码量。 Stream常用方法 Stream流对象的五种创建方式 //基于数组 String[] arr {"a","b","c…...

ROG STRIX GS-AX5400 使用笔记

1. 技术支持 咨询京东&#xff08;因为是在京东购买的&#xff09; 2. 增强信号设置 Note&#xff1a;关于设置的具体步骤&#xff0c;请参考教程《华硕路由器地区如何改成澳大利亚》。 操作路径&#xff1a;打开主页<192.168.50.1> ⇒ 输入用户名和密码后选择登录 ⇒ …...

【刷题-PTA】堆栈模拟队列(代码+动态图解)

【刷题-PTA】堆栈模拟队列(代码动态图解) 文章目录 【刷题-PTA】堆栈模拟队列(代码动态图解)题目输入格式:输出格式:输入样例:输出样例: 分析题目区分两栈解题思路伪代码动图演示代码测试 题目 题目描述 : 设已知有两个堆栈S1和S2&#xff0c;请用这两个堆栈模拟出一个队列Q。 …...

FileUpload控件上传文件时出现 不支持给定路径的格式.的解决方法

正常代码&#xff0c;部署到server 2012时&#xff0c;在上传音频mp3文件时&#xff0c;显示错误“不支持给定路径的格式”&#xff0c;上传控件使用FileUpload控件&#xff1a; 因为程序之前是正常的&#xff0c;因此应该不是程序的问题。 上传时&#xff0c;发现在选择文件时…...

这两天的一些碎碎念

一直以来我都不算是一个非常热爱运维岗位的一个人&#xff0c;其实本行工作对于我来说只是一个工作。运维的广度很大&#xff0c;说什么工作了7年了&#xff0c;可最终总感觉还曾是一窍不通。 什么shell啊&#xff0c;什么python啊&#xff0c;什么大数据啊&#xff0c;7年里&a…...

Unity 最新DOTS系列之《Baking与Baker的详解》

Unity DOTS Baking与Baker详解 最近DOTS终于发布了正式的版本, 我们来分享一下DOTS里面Baking 与Baker的关键概念&#xff0c;方便大家上手学习掌握Unity DOTS开发。 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点击进来一起交流一下开发经验呀&…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...