里氏替换原则——举例说明Java设计模式中的里氏替换原则
里氏替换原则——举例说明Java设计模式中的里氏替换原则
- 1. 前言
- 官方定义:
- 2. 举例说明
- 2.1 例子介绍
- 2.2 反例
- 2.2.1 类图说明
- 2.2.2 代码说明
- 2.2.3 测试
- 2.2.4 分析优缺点
- 2.3 正例
- 2.3.1 类图说明
- 2.3.2 代码说明
- (1)抽取基类(父类)-->ChooseSweater
- (2)倾向中性服饰子类-->NeutralChooseSweater
- (3)倾向女性服饰子类-->GirlChooseSweater
- 2.3.3 测试
- 2.3.4 分析优缺点
- 3. 总结
- 使用继承?
- 如何使用继承?
- 里氏替换原则作用
- 4. 附代码
- 反例
- 正例
1. 前言
- 里氏替换原则(Liskov Substitution Principle,LSP),为什么叫里氏替换?因为是由麻省理工学院的一位姓李的女士提出来的。
官方定义:
- 如果对每一个类型为 P 的对象 op1,都有类型为 S 的对象 os1,使得以 P 定义的所有程序 Px 在所有的对象 oP1 都代换成 os1 时,程序 Px 的行为没有发生变化,那么类型 S 是类型 T 的子类型。
- 定义可理解为:所有引用基类的地方必须能透明地使用其子类的对象。
- 白话就是说:用类型为子类的对象 os1 调用 “父类的所有方法” 时,父类没有方法没有被重写(行为没有发生变化),即完全继承。
2. 举例说明
2.1 例子介绍
- 平时购物狂的我,今天拿购买衣服为例子说明一下里氏替换原则。
- 反例里有两个类:
NeutralChooseSweater–>倾向中性衣服类,作为父类
GirlChooseSweater–>倾向女性服装类,作为NeutralChooseSweater的子类,继承了 NeutralChooseSweater 来的属性和方法,但是重写了其中一个方法 chooseNeutralClothes(),问题就出现了,我们往下看例子…… - 下面案例的意思是:先后进店的是两个漂亮女孩,服务员就给他们推荐了漂亮的女性服饰,第一个女孩进来用类型为父类的对象调用chooseNeutralClothes()方法没问题,但是第二个女孩进来,用类型为子类的对象chooseNeutralClothes()方法,以为还是调用的继承父类过来的方法,但是谁知方法已被子类重写,所以出现问题。
2.2 反例
2.2.1 类图说明
2.2.2 代码说明
- 先看父类–>NeutralChooseSweater
- 再看子类–>GirlChooseSweater
2.2.3 测试
2.2.4 分析优缺点
- 从上面例子可以看到,原本可以正常运行的程序出现了功能异常问题,原因就是子类无意中重写了父类的方法,或者调用的时候以为还是调用子类继承过来的父类方法,造成原有功能不能实现。
- 在实际开发中,经常会通过重写父类的方法完成新的功能,这样虽然简单,但是会让整个继承体系的复用性变得很差,特别是运行多态比较繁琐的时候。
- 那怎么优化呢?
就是下面我们的正例所实现的,抽取原来的父类和子类的公共部分作为一个基类(他们共有的新的父类),原有的两个类的继承关系去掉(都继承新的基类),采用依赖,聚合,组合等关系代替,请继续……
2.3 正例
2.3.1 类图说明
2.3.2 代码说明
(1)抽取基类(父类)–>ChooseSweater
(2)倾向中性服饰子类–>NeutralChooseSweater
(3)倾向女性服饰子类–>GirlChooseSweater
2.3.3 测试
2.3.4 分析优缺点
- 上面就是我们遵循里氏替换原则后的代码,让新的基类作为他们父类,降低了原有父子类的耦合关系。
- 反例中,父被子替换后(GirlChooseSweater girlChooseSweater = new GirlChooseSweater();),再调用父类的程序chooseNeutralClothes(),程序的行为发生了变化,即违背了里氏替换原则。
- 而里氏替换原则是:
白话理解就是,父类的方法子类也可以同等生效,并且将父类用子类替换后,也不会产生任何问题。但是,需要注意的是里氏替换原则告诉我们反过来使用是不行的,子类重写后特有的方法,父类未必适用。
简单粗暴的道理就是:单身爹的遗产儿子继承,儿子的遗产第一继承人不是爹是老婆大人,所以爹和儿子都能继承的遗产是儿子妈的,此时妈妈是基类。
3. 总结
使用继承?
- 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。
- 继承在给程序设计带来便利的同时也带来了弊端。使程序的可移植性降低,也增强了对象间的耦合性。在父子类中,如果父类需要修改,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能出现问题。
如何使用继承?
- 使用继承时,子类中尽量不要重写父类的方法;
即:在实际使用中,采用里氏替换原则应当尽量避免子类的“个性”,一旦子类产生“个性”,这个子类和父类之间的关系将难以调和。 - 所有引用基类的地方必须能透明地使用子类的对象。开发中使用继承会增强两个类之间的耦合性,在适当的情况下,可以通过聚合、组合、依赖来解决问题(如本文的正例)。这就是在遵守里氏替换原则下,使用继承。
里氏替换原则作用
- 采用里氏替换原则的目的是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的父类仍然可以运行。
4. 附代码
反例
package com.liu.susu.principle.liskov.example1;/*** @FileName ChooseNeutralClothes* @Description 中性衣服类* @Author susu* @date 2022-02-15**/
public class NeutralChooseSweater {String type;//0:女服装 1:男服装 2:中性服装/*** @Description: 指定尺寸的方法*/public void chooseXLClothes(){System.out.println("seller-->ok,给您挑选了一件XL的毛衫,您先试试……");}/*** @Description: 指定红色衣服的方法*/public void chooseRedClothes(){System.out.println("seller-->ok,给您挑选了一件红色的毛衫,您先试试……");}/*** @Description: 不指定尺寸的挑选*/public void chooseNeutralClothes(){System.out.println("seller-->ok,给您随便选了一件overSize的中性毛衫,您先试试……");this.type = "2";//倾向中性this.replyInfoFromGirls();//为了更好的理解应用场景,我们来个对话}/*** @Description: 收到部分女性顾客(但是更倾向于中性服装)的回应*/public void replyInfoFromGirls(){if ("0".equals(type)){System.out.println("girl-->Oh,No! I'm a girl,but I prefer to pick a neutral sweater!! ");}else if("1".equals(type)){System.out.println("girl-->我喜欢中性点的服装,这个更倾向于男性,不过,我觉得还算ok!");}else {System.out.println("girl-->Neutral sweater! Thank you!My preference!");}}
}
/*** GirlChooseSweater-->更倾向于女性的服装类*/
class GirlChooseSweater extends NeutralChooseSweater{/*** @Description: 不指定尺寸的挑选*/@Overridepublic void chooseNeutralClothes(){System.out.println("seller-->ok,给您选了一件今年特别流行的、百搭的、女孩们都喜欢的款式,您先试试……");this.type = "0";//倾向女性this.replyInfoFromGirls();//为了更好的理解应用场景,我们来个对话}}class ClientTest {public static void main(String[] args) {System.out.println("旁白-->The first beautiful girl is coming!");NeutralChooseSweater neutralChooseSweater = new NeutralChooseSweater();neutralChooseSweater.chooseNeutralClothes();System.out.println("\n旁白-->The second beautiful girl is coming!");GirlChooseSweater girlChooseSweater = new GirlChooseSweater();girlChooseSweater.chooseNeutralClothes();//以为还是父类的中性服装方法,结果被重写了System.out.println("\ngirl-->那先给我朋友来一件红色的毛衫吧,我待会儿再选,,");girlChooseSweater.chooseRedClothes();}
}
正例
package com.liu.susu.principle.liskov.example2;
/*** @FileName ChooseSweater* @Description 用基类 ChooseSweater 作为 NeutralChooseSweater 和 GirlChooseSweater 的父类* 抽取他们的公共部分* @Author susu* @date 2022-02-15**/
public class ChooseSweater {String type;//0:女服装 1:男服装 2:中性服装/*** @Description: 指定尺寸的方法*/public void chooseXLClothes(){System.out.println("seller-->ok,给您挑选了一件XL的毛衫,您先试试……");}/*** @Description: 指定红色衣服的方法*/public void chooseRedClothes(){System.out.println("seller-->ok,给您挑选了一件红色的毛衫,您先试试……");}/*** @Description: 收到部分女性顾客(但是更倾向于中性服装)的回应*/public void replyInfoFromGirls(){if ("0".equals(type)){System.out.println("girl-->Oh,No! I'm a girl,but I prefer to pick a neutral sweater!! ");}else if("1".equals(type)){System.out.println("girl-->我喜欢中性点的服装,这个更倾向于男性,不过,我觉得还算ok!");}else {System.out.println("girl-->Neutral sweater! Thank you!My preference!");}}
}/*** @FileName ChooseNeutralClothes* @Description 中性衣服类* @Author susu* @date 2022-02-15**/class NeutralChooseSweater extends ChooseSweater{/*** @Description: 不指定尺寸的挑选--主要是倾向中性的*/public void chooseNeutralClothes(){System.out.println("seller-->ok,给您随便选了一件overSize的中性毛衫,您先试试……");this.type = "2";//倾向中性this.replyInfoFromGirls();//为了更好的理解应用场景,我们来个对话}}/*** GirlChooseSweater-->更倾向于女性的服装类*/
class GirlChooseSweater extends ChooseSweater{//降低GirlChooseSweater 与 NeutralChooseSweater 之间的耦合性private NeutralChooseSweater neutralChooseSweater = new NeutralChooseSweater();/*** @Description: 不指定尺寸的挑选--主要是倾向中性的*/public void chooseNeutralClothes(){neutralChooseSweater.chooseNeutralClothes();}/*** @Description: 不指定尺寸的挑选--主要是倾向挑选女性服装的*/public void chooseToGirlClothes(){System.out.println("seller-->ok,给您选了一件今年特别流行的、百搭的、女孩们都喜欢的款式,您先试试……");System.out.println("girl-->Thank you very much!");}}class ClientTest {public static void main(String[] args) {System.out.println("旁白-->The first beautiful girl is coming!");NeutralChooseSweater neutralChooseSweater = new NeutralChooseSweater();neutralChooseSweater.chooseNeutralClothes();System.out.println("\n旁白-->The second beautiful girl is coming!");GirlChooseSweater girlChooseSweater = new GirlChooseSweater();girlChooseSweater.chooseNeutralClothes();//这个时候就不会弄错了,因为里面调用的就是neutralChooseSweater.chooseNeutralClothes();System.out.println("\ngirl-->再来一件女孩们都喜欢的,送给我的朋友,,");girlChooseSweater.chooseToGirlClothes();}
}
里氏替换原则——举例说明Java设计模式中的里氏替换原则相关推荐
- 依赖倒置原则——举例说明Java设计模式中的依赖倒置原则
依赖倒置原则--举例说明Java设计模式中的依赖倒置原则 一.前言 看官方定义 二.举例说明 2.1 例子介绍(无聊的可看看,着急的请跳过) 2.2 反例 2.1.1 反例1 (1)类图说明 (2)代 ...
- 接口隔离原则——举例说明Java设计模式中的接口隔离原则
举例说明Java设计模式中的接口隔离原则 一.举例说明 1.反例 (1)类图说明 (2)代码说明 (3)测试 (4)分析缺点(总结) 2.正例 (1)类图说明 (2)代码说明 (3)测试 (4)方案评 ...
- Java设计模式中的六大设计原则
最近一直在看有关设计模式的博客和文章,发现自己对于设计模式的认识和理解还是有点浅显,于是想动手写博客巩固一下. 在开始阐述设计模式之前,首先介绍一下设计模式中的六大原则: 总原则-开闭原则 ...
- java设计模式3,里氏替换原则
目录 一.里氏替换原则定义 二.里氏替换原则的作用 三.违背原则场景 四.里氏替换原则改变代码 1.抽象人物类 2.哪吒子类 3.敖丙子类 五.关注公众号哪吒编程,回复1024,获取Java学习资料, ...
- 引用防删——JAVA设计模式总结之六大设计原则
JAVA设计模式总结之六大设计原则 从今年的七月份开始学习设计模式到9月底,设计模式全部学完了,在学习期间,总共过了两篇:第一篇看完设计模式后,感觉只是脑子里面有印象但无法言语.于是决定在看一篇,到9 ...
- 设计模式中的开闭原则
Table of Contents 1 设计模式中的开闭原则 1.1 基本原则 2 模式中的开-闭原则 2.1 策略模式 2.2 简单工厂 2.3 工厂方法 2.4 抽象工厂 2.5 建造者模式 2. ...
- Java设计模式中的单例模式
有时候在实际项目的开发中,我们会碰到这样一种情况,该类只允许存在一个实例化的对象,不允许存在一个以上的实例化对象,我们将这种情况称为Java设计模式中的单例模式.设计单例模式主要采用了Java的pri ...
- Java 设计模式总结及六大设计原则
设计模式总结 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式. ...
- java设计模式总结之六大设计原则(有图有例子)
转载:https://www.cnblogs.com/jpfss/p/9765239.html 下面来总结下自己所学习的设计模式,首先我们看下各个模式之间的关系图,下面这张图是网上比较典型的一个类图关 ...
最新文章
- mysql双主使用reset master清除日志要小心
- 最大输入hdu 2534 规律水题 求任意个a,b的和 不能表示的最大的数
- [快速数论变换 NTT]
- 敏捷个人2012.7月份线下活动报道:珠海 时中法、深圳 敏捷个人理念
- RabbitMQ(六)整合SpringBoot
- 计算机二级考点的选择题,2016年计算机二级考试试题选择题
- java 垃圾回收 新生代_Java垃圾回收
- 大数据可视化的优点有哪些
- 华为v3鸿蒙系统_重磅!华为鸿蒙系统问世!
- python代理ip连接失败_遇到问题--python--爬虫--使用代理ip第二次获取代理ip失败
- 云计算成就代码之美——首届阿里云开发者大赛巡礼
- 区块链ICO是什么意思?回答所有你关于ICO的问题
- html自动调音量,HTML5 音量调节控件
- 虚拟机安装和优盘启动盘制作
- 计算机科学与生命科学的关系,计算机科学与生命科学论文
- 折线分割平面问题总结
- 2023东莞理工学院计算机考研信息汇总
- 火狐浏览器firefox检测不到U盾证书
- JavaScript事件——【小案例】小人快跑
- MATLAB人工神经网络的手写数字识别系统
热门文章
- 深夜碎碎念,肿瘤NGS基因检测的寒冬
- 取消改写模式(python)
- [spring源码学习]六、IOC源码-BeanFactory和factory-bean
- 【FPGA——工具篇】:Modelsim SE-64 10.4下载、破解、安装过程
- 医学应用计算机答案,医学计算机应用试题及答案大全02.doc
- unity开发xbox手柄 驱动坑
- python分段函数编写程序_python分段函数如何编写?
- oracle中的userenv,Oracle 中的userenv()
- IOS开发百度地图API入门到精通-用点生成路线,导航,气泡响应
- 海豹突击队体能训练手册——前言