04.里氏替换原则(Liskov Substitution Principle)

暴论:一般的,如果一个富二代不想着证明自己,那么他一辈子都会衣食无忧。

一言

里氏替换原则想告诉我们在继承过程中会遇到什么问题,以及继承有哪些注意事项。


概述

这是流传较广的一个段子:

“一个坐拥万贯家财的富二代,他可以终日花天酒地,飞扬跋扈,跑车炸街,美女为伴,极尽荒唐之能事。只要他不想着证明自己比父亲强,让父辈的产业按既定的规则运转,那么他将一生衣食无忧。”

在这里插入图片描述
看似戏谑的言论实则透露出的是一种稳健的合理。在父辈足够优秀,后人的能力又并非出类拔萃的情况下,不打破既有的优秀机制无疑是最稳妥的选择。段子归段子,玩笑归玩笑。在软件设计中,我们会经常遇到父类子类的继承关系,这个看似荒唐又合理的原则实际上就是里氏替换原则的精髓

OO中的继承性

继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏
继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。
于是里氏替换原则提供了针对这种问题的规范。

何为里氏替换原则

里氏替换原则在1988年由麻省理工学院的**芭芭拉·里斯克夫(Barbara Liskov)**女士提出。
如果对每个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象。
在使用继承时,子类尽量不要重写父类的方法。继承实际让两个类的耦合性增强了,在适当的情况下可以通过聚合、组合、依赖来解决问题。


三寸反骨

我们还是从一个反骨仔的故事开始,为什么里氏替换原则不让重写父类方法?我就要重写父类方法!
反例

public class Story {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("100-50 = "+a.func1(100,50));
        System.out.println("100-200 = "+a.func1(100,200));

        System.out.println("-------------------------------");
        B b = new B();
        System.out.println("100-50 = "+b.func1(100,50));
        System.out.println("100-200 = "+b.func1(100,200));
        System.out.println("(100+200)*10 = "+b.func2(100,200));
    }
}

class A{
    public int func1(int a, int b){
        return a-b;
    }
}

class B extends A{
    public int func1(int a, int b){
        return a+b;
    }

    public int func2(int a, int b){
        return func1(a, b)*10;
    }
}

当反骨仔随心所欲的继承重写之后:
在这里插入图片描述
我们发现原本运行正常的相减功能发生了错误。原因就是类B无意中重写了父类的方法,造成原有功能出现错误。在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候。
子类过分的逆反使得代码极难维护,甚至随着代码量的扩张,真的是牵一发而动全身。


克己正心

听人劝,吃饱饭。反骨仔经过实践之后觉得这个继承之后的重写确实要慎重。那么究竟要如何去优化呢?
通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉采用依赖,聚合,组合等关系代替。
在这里插入图片描述
于是经过深思熟虑的代码出现了:

public class Story {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("100-50="+a.func1(100,50));
        System.out.println("100-200="+a.func1(100,200));
        System.out.println("---------------------------------");
        B b = new B();
        //因为B类不再继承A类,因此调用者,不会在func1求减法
        System.out.println("100+50="+b.func1(100,50));
        System.out.println("100+200="+b.func1(100,200));
        System.out.println("(100+200)*10="+b.func2(100,200));
        System.out.println("---------------------------------");
        System.out.println("使用组合依然可以使用到A的方法");
        System.out.println("100-50="+b.func3(100,50));
    }
}
class Base{
}
class A extends Base{
    public int func1(int num1,int num2){
        return num1-num2;
    }
}
class B extends Base {
    private A a = new A();
    public int func1(int a, int b) {
        return a + b;
    }
    public int func2(int a, int b) {
        return func1(a, b) * 10;
    }
    public int func3(int a, int b) {
        return this.a.func1(a, b);
    }
}

我们采用引入基类,子类组合的方式淡化反骨仔的继承关系,进而削弱A、B业务之间的冲突,在一定程度上解耦合。提高了灵活性的同时,也遵循了里氏替换原则。
在这里插入图片描述


里氏替换原则面向类与类之间的继承关系提出了设计规范,在一定程度上规避了业务设计上的杂糅,使得方法在继承关系中更纯粹,也使得设计在扩展方面具有更好的管理性。
事实上,与这个理论很相近的开闭原则才是所有设计的核心。关于开闭原则的拆解我们下次继续!


关注我,共同进步,每周至少一更!——Wayne

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/219388.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

博客文章SEO:提升博客排名和吸引更多读者的方法来啦!

互联网发展到现在,搜索引擎优化(SEO)一直发挥着不可替代的作用。搜索引擎的流量往往更加定向,来自搜索引擎的流量转化率更高,可以帮助企业更好地实现销售和推广目标。因此,通过合理的SEO策略,你…

Data Linked UI

DataLinkedUl是一个Unity框架,它允许您在为您的应用程序创建用户界面时实现专业的数据驱动方法。使用此资产,您可以创建灵活的基于瓦片的任意大小的复杂接口系统。 核心功能: 灵活性-允许适应和调整数据变化,允许各种结构和功能配置,而不需要对现有系统进行重大破坏。 可伸…

跨境独立站反向代购系统是什么?如何搭建?

淘宝代购是近年兴起的一种购物模式,是帮国外客户购买中国商品。主要是通过万邦 科技的外贸代购系统,把淘宝、天猫等电商平台的全站商品通过API 接入到你的网站 上,瞬间就可以架设一个有数亿产品的大型网上商城,而且可以把这些中文…

BFD多跳检测配置

定义 双向转发检测BFD(Bidirectional Forwarding Detection)是一种全网统一的检测机制,用于快速检测、监控网络中链路或者IP路由的转发连通状况。 目的 为了减小设备故障对业务的影响,提高网络的可靠性,网络设备需要…

Hadoop学习笔记(HDP)-Part.16 安装HBase

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

暂时pass的题目的学习笔记(按类型分类 ):动态规划、递归

动态规划类 学习笔记来自公众号labuladong 动态规划的一般形式就是求最值——其核心问题是穷举但动态规划的穷举有些特别,因为这类问题存在重叠子问题 如果暴力穷举的话效率会极其低下,所以需要**「备忘录」或者「DP table」**来优化穷举过程&#xff…

广州华锐视点:VR仿真实训室中控系统成为VR课堂教学必备工具

随着科技的不断发展,虚拟现实(VR)技术已经逐渐走进我们的生活。从游戏娱乐到医疗教育,VR技术的应用范围日益广泛。近年来,VR技术在教育领域的应用也取得了显著的成果,为提高教育质量和培养创新人才提供了全…

【Linux】less 命令使用

less命令 less 与 more 类似。 less是一个非常常用的文本查看工具,它可以用于查看任意大小的文本文件,支持滚动翻页、搜索、标记等功能。在本文中,我们将详细介绍less命令的用法、参数和实例,并对其背后的原理和相关技术进行简要…

Spring 的设计思想、创建和使用、Bean 作用域和生命周期

文章目录 Spring 设计思想Spring 是什么?什么是 IoC? Spring 创建和使用创建 Spring 项目注册 Bean 对象获取并使用 Bean 对象 Spring 更方便地存储和读取对象配置文件使用注解使用类注解使用方法注解 获取 Bean 对象属性注入Setter 注入构造方法注入Res…

ORACLE数据库实验总集 实验二 Oracle数据库逻辑存储结构管理

一、实验目的 (1)掌握 Oracle数据库表空间的管理 (2)掌握数据库表空间不同状态时对数据操作的影响。 二、实验要求 (1)分别创建永久性表空间、临时性表空间、撤销表空间 (2)完成表…

Vue--第六天

vuex概述: 组件通信感觉有点白雪。。。。。。。。。。 创建项目: 为了学习简介,先选几个,后续是要勾选很多的 建好后再进行组件导入 创建空仓库: 使用: 上面是store访问,下面是辅助函数的方式…

2023年个人工作总结怎么写?工作任务完成自动记录的待办软件

2023年已经接近尾声,不少人已经开始期待新的一年到来了。不过对于大多数职场人士来说,最近还有一项让人头疼的任务需要完成,这就是撰写2023年个人工作总结。 那么年度个人工作总结怎么写呢?其实很简单,年度工作总结一…

5、RocketMQ-Producer生成消息过程 (五)

生产者已经被启动了,接下来我们就得研究研究如何去发送消息给Broker。 前面分析Producer的启动逻辑,启动完成之后就是发消息,接下来我们就来分析Producer的send消息过程,同时发消息过程中存在一些问题以及解决方法也得考虑。 查…

Java POI读写Excel文档

Java POI读写Excel文档 简介 由apache公司提供Java编写的免费开源的跨平台的Java API提供API给Java程序对Microsoft Office格式档案读和写的功能 包结构 HSSF读写Microsoft Excel XLS(2003版本的Excel)XSSF读写Microsoft Excel OOXML XLSXHWPF读写Microsoft Word DocHSLF提…

Honeywell PM43 loadfile.lp RCE漏洞复现(CVE-2023-3710)

0x01 产品简介 Honeywell PM43 是美国霍尼韦尔(Honeywell)公司的一款打印机产品。 0x02 漏洞概述 Honeywell PM43 P10.19.050004之前版本存在输入验证错误漏洞,攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获…

行云海CMS SQL注入漏洞复现

0x01 产品简介 行云海cms是完全开源的一套CMS内容管理系统,简洁,易用,安全,稳定,免费。 0x02 漏洞概述 行云海cms中ThinkPHP在处理order by排序时可利用key构造SQL语句进行注入,LtController.class.php中发现传入了orderby未进行过滤导致sql注入。攻击者除了可以利用 SQL 注入…

关于 Python 的最全面试题

1 Python的函数参数传递 看两个例子: a 1 def fun(a):a 2 print a # 1a [] def fun(a):a.append(1) print a # [1]所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。 这里记住的是类型是属于对象的,而…

Python使用netmiko配置华为交换机

一、netmiko介绍 1.更适合网络设备的自动化运维模块。 二、场景 1、批量查询 2、批量配置变更、备份 三、项目地址 GitHub - ktbyers/netmiko: Multi-vendor library to simplify Paramiko SSH connections to network devices 三、使用步骤 1.安装netmiko pip install ne…

【带头学C++】----- 九、类和对象 ---- 9.5 初始化列表

目录 9.5 初始化列表 9.5.1 对象成员 代码: 9.5.2 初始化列表 9.5 初始化列表 9.5.1 对象成员 在类中定义的数据成员一般都是基本的数据类型。但是类中的成员也可以是对象,叫做对象成员。 先调用对象成员的构造函数,再调用本身的构造函数…

几句对话就能生成简历?“搜索界奥林匹克”上演AI原生应用开发热潮

只需要回答几个问题,就能生成个性化的简历,还提供优化建议,安排AI模拟面试。这样的效率神器,就出现第二届百度搜索创新大赛的赛场上。 来自南京航空航天大学的“肝到凌晨”团队,利用文心一言插件平台“灵境矩阵”和百度…