七大设计原则之里氏替换原则

devtools/2025/1/22 4:42:58/

目录

一、什么是里氏替换原则

二、里氏替换原则的应用

三、不符合里氏替换原则的情况


一、什么是里氏替换原则

        里氏替换原则,英文叫Liskov Substitution Principle,简称LSP(老色皮,哈哈)。里氏替换原则,其实是没有我们前面,说的SRP和OCP比较见名知意一些。根据他们两个的中文名称,我们都很容易联想到他的定义。比如,单一职责原则,就是一个类或者模块只负责一个职责。而开闭原则,根据名字,我们也不难得知其定义就是,对扩展开发,对修改关闭。然而,里氏替换原则,根据名称,我们却难以得知其到底有何含义。

        里氏替换,其实重点就在后面的替换两字。我们来看里氏替换的一般定义:“派生类(子类)对象可以在程序中代替其基类(超类)对象”。也就是说,在父类对象出现的地方,子类对象都可以进行替换,并且这个替换是要保证原来的逻辑行为不变以及正确性不变。所以,在结合这个名字,里氏替换,好像也不难那么理解了。里氏替换,谐音"理是替换"。也就是子类对象替换父类对象一定是要符合道理的,而这个道理就是上述说的,保证逻辑行为以及正确性不变。

二、里氏替换原则的应用

        比如有这样一个场景,我们需要开发一个自定义系统监控探针,这个自定义监控的探针可以监控linux、windows、aix等操作系统。这个核心逻辑的步骤大致就是如下两步:

1、使用对应操作系统命令获取指标信息。

2、将获取的指标信息进行封装处理,比如将获取的指标信息按照某一个格式封装处理然后推送到某个统一监控的中间组件上等。

显而易见,第一步的获取操作系统指标是变化的,而第二步封装处理等操作,我们暂且当作不管任何操作系统都是一样的处理。那么此时,我们就可以使用里氏替换原则,来使得第二步的代码具有更高的灵活性、复用性等。

比如,针对第一步,我们可以先定义一个如下接口:

java">public interface SystemMonitorMetricDao {Object queryCpuUtilizationInfo();Object queryCpuCoreNumInfo();SystemDiskMetricInfo queryDiskInfo();SystemBaseMetricInfo queryMemoryInfo();
}

接着,我们定义三个具体的实现类,它们分别针对Linux、Windows和AIX系统,负责获取各自的监控指标。

aix系统指标获取实现类如下:

java">public class AixSystemMonitorMetricImpl implements SystemMonitorMetric {@Overridepublic Object queryCpuUtilizationInfo() {Double cpu = Double.valueOf(0);//省略具体逻辑代码..........return cpu;}@Overridepublic Object queryCpuCoreNumInfo() {Integer cpuCore = 0;//省略具体逻辑代码..........return cpuCore;}@Overridepublic SystemDiskMetricInfo queryDiskInfo() {SystemDiskMetricInfo systemDiskMetricInfo = new SystemDiskMetricInfo();//省略具体逻辑代码..........return systemDiskMetricInfo;}@Overridepublic SystemBaseMetricInfo queryMemoryInfo() {SystemBaseMetricInfo systemBaseMetricInfo = new SystemBaseMetricInfo();//省略具体逻辑代码..........return systemBaseMetricInfo;}}

 linux系统指标获取实现类如下:

java">public class LinuxSystemMonitorMetricImpl implements SystemMonitorMetric {@Overridepublic Object queryCpuUtilizationInfo() {Double cpu = Double.valueOf(0);//省略具体逻辑代码..........return cpu;}@Overridepublic Object queryCpuCoreNumInfo() {Integer cpuCore = 0;//省略具体逻辑代码..........return cpuCore;}@Overridepublic SystemDiskMetricInfo queryDiskInfo() {SystemDiskMetricInfo systemDiskMetricInfo = new SystemDiskMetricInfo();//省略具体逻辑代码..........return systemDiskMetricInfo;}@Overridepublic SystemBaseMetricInfo queryMemoryInfo() {SystemBaseMetricInfo systemBaseMetricInfo = new SystemBaseMetricInfo();//省略具体逻辑代码..........return systemBaseMetricInfo;}}

 windwos系统指标获取实现类如下:

java">public class WindowsSystemMonitorMetricImpl implements SystemMonitorMetric {@Overridepublic Object queryCpuUtilizationInfo() {Double cpu = Double.valueOf(0);//省略具体逻辑代码..........return cpu;}@Overridepublic Object queryCpuCoreNumInfo() {Integer cpuCore = 0;//省略具体逻辑代码..........return cpuCore;}@Overridepublic SystemDiskMetricInfo queryDiskInfo() {SystemDiskMetricInfo systemDiskMetricInfo = new SystemDiskMetricInfo();//省略具体逻辑代码..........return systemDiskMetricInfo;}@Overridepublic SystemBaseMetricInfo queryMemoryInfo() {SystemBaseMetricInfo systemBaseMetricInfo = new SystemBaseMetricInfo();//省略具体逻辑代码..........return systemBaseMetricInfo;}}

第二步的实现大概就如下:

java">public class SystemMonitorService {public void systemMonitor(SystemMonitorMetric systemMonitorMetric) {IMetricQueryService metricQueryService = BeanFactory.getMetricQueryService();//根据传入的具体实现类获取指标数据List<PushMetricToPrometheusParam> paramList = metricQueryService.queryMetricInfo(systemMonitorMetric);if (paramList == null || paramList.size() == 0) return;//发送指标到pushGatewaysendMetricsToPushGateway(paramList);      }

里氏替换:

java">   public static void main(String[] args) {// 创建 SystemMonitorService  和 AixSystemMonitorMetricImpl对象SystemMonitorService systemMonitorService = new SystemMonitorService();SystemMonitorMetric systemMonitorMetric = new AixSystemMonitorMetricImpl();//调用系统监控方法,监控不同得系统就传入不同得具体实现,这里监控得aix系统,所以就传入得aix系统指标获取得实现类systemMonitorService.systemMonitor(systemMonitorMetric);  }

在上面的代码设计中,子类AixSystemMonitorMetricImpl、LinuxSystemMonitorMetricImpl以及WindowsSystemMonitorMetricImpl的设计完全符合里式替换原则,可以替换父类出现的任何位置,并且原来代码的逻辑行为不变且正确性也没有被破坏。

那么,此时可能会有人说了,这里氏替换不就是多态吗?

其实不然。多态是面向对象编程的一个特点,也是编程语言里的一种用法。它让我们知道怎么实现代码。里氏替换是个设计规矩,告诉我们怎么设计继承里的子类。子类要能代替父类,但不能改原来程序的逻辑,也不能让程序出错。就是说,里氏替换在多态的基础上,多了个不让程序逻辑和正确性变的要求。

三、不符合里氏替换原则的情况

1、子类违背父类声明要实现的功能

2、子类违背父类对输入、输出、异常的约定

3、子类违背父类注释中所罗列的任何特殊说明 


http://www.ppmy.cn/devtools/152501.html

相关文章

前端调试【详解】含debugger,console,断点,手机真机调试等

Web 端 alert 调试 - 阻塞 【重要】debugger 调试 - 阻塞 https://blog.csdn.net/weixin_41192489/article/details/123872064 控制台 API 调试 https://blog.csdn.net/weixin_41192489/article/details/123872064 【重要】console 调试 https://blog.csdn.net/weixin_41…

R 语言科研绘图第 20 期 --- 箱线图-配对

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…

Solidity03 Solidity变量简述

文章目录 一、变量简述1.1 状态变量1.2 局部变量1.3 全局变量1.4 注意问题 二、变量可见性2.1 public2.2 private2.3 internal2.4 默认可见性2.5 可见性的用处 三、变量初始值3.1 值类型初始值 一、变量简述 变量是指可以保存数据的内部存储单元&#xff0c;里面的数据可以在程…

jenkins-api操作

一. 简述&#xff1a; 在一个比较复杂的环境中&#xff0c; 往往会有自己开发的运维管理平台。在代码发布这块&#xff0c;尽管jenkins有一个比较方便的UI&#xff0c; 但很多团队还是喜欢集中式管理&#xff0c; 将发布功能(仅仅把jenkins作为一个发布组件使用)嵌入运维管理平…

【Spring MVC】如何运用应用分层思想实现简单图书管理系统前后端交互工作

前言 &#x1f31f;&#x1f31f;本期讲解关于SpringMVC的编程思想之应用分层~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那…

数据库的DQL(3)

数据库的DQL(3) 分组查询 在MySQL中&#xff0c;group by关键字可以根据一个或多个字段对查询结果进行分组 group by 字段名1.分组函数 有时也叫聚合函数 count(): 查询表中的记录数量avg(): 求平均值sum(): 求和max():求最大值min():求最小值 案例1&#xff1a; mysql&g…

深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化

目录 什么是协同过滤算法核心原理基本步骤相似度计算代码实现详解1.流程图2.创建基础的数据结构存储用户评分数据3.计算用户相似度4.获取相似用户5.推荐方法 算法优化建议1. 数据预处理优化去除异常值和噪声数据进行数据标准化使用稀疏矩阵优化存储 2. 相似度计算优化使用局部敏…

STM32使用DSP库 Keil方式添加

文章目录 前言一、添加DSP库二、使能FPU及配置1. 使能FPU2. 增加编译的宏3.增加头文件的检索路径三. 验证1. 源码中添加2.代码测试前言 添加DSP有两种方案,本文采用的是是Keil 中添加。 一、添加DSP库 在创建好的工程中添加DSP库:步骤如下: 步骤1:选择运行环境管理; 步…