里氏替换原则——举例说明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设计模式中的里氏替换原则相关推荐

  1. 依赖倒置原则——举例说明Java设计模式中的依赖倒置原则

    依赖倒置原则--举例说明Java设计模式中的依赖倒置原则 一.前言 看官方定义 二.举例说明 2.1 例子介绍(无聊的可看看,着急的请跳过) 2.2 反例 2.1.1 反例1 (1)类图说明 (2)代 ...

  2. 接口隔离原则——举例说明Java设计模式中的接口隔离原则

    举例说明Java设计模式中的接口隔离原则 一.举例说明 1.反例 (1)类图说明 (2)代码说明 (3)测试 (4)分析缺点(总结) 2.正例 (1)类图说明 (2)代码说明 (3)测试 (4)方案评 ...

  3. Java设计模式中的六大设计原则

    最近一直在看有关设计模式的博客和文章,发现自己对于设计模式的认识和理解还是有点浅显,于是想动手写博客巩固一下. 在开始阐述设计模式之前,首先介绍一下设计模式中的六大原则:      总原则-开闭原则 ...

  4. java设计模式3,里氏替换原则

    目录 一.里氏替换原则定义 二.里氏替换原则的作用 三.违背原则场景 四.里氏替换原则改变代码 1.抽象人物类 2.哪吒子类 3.敖丙子类 五.关注公众号哪吒编程,回复1024,获取Java学习资料, ...

  5. 引用防删——JAVA设计模式总结之六大设计原则

    JAVA设计模式总结之六大设计原则 从今年的七月份开始学习设计模式到9月底,设计模式全部学完了,在学习期间,总共过了两篇:第一篇看完设计模式后,感觉只是脑子里面有印象但无法言语.于是决定在看一篇,到9 ...

  6. 设计模式中的开闭原则

    Table of Contents 1 设计模式中的开闭原则 1.1 基本原则 2 模式中的开-闭原则 2.1 策略模式 2.2 简单工厂 2.3 工厂方法 2.4 抽象工厂 2.5 建造者模式 2. ...

  7. Java设计模式中的单例模式

    有时候在实际项目的开发中,我们会碰到这样一种情况,该类只允许存在一个实例化的对象,不允许存在一个以上的实例化对象,我们将这种情况称为Java设计模式中的单例模式.设计单例模式主要采用了Java的pri ...

  8. Java 设计模式总结及六大设计原则

    设计模式总结 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式. ...

  9. java设计模式总结之六大设计原则(有图有例子)

    转载:https://www.cnblogs.com/jpfss/p/9765239.html 下面来总结下自己所学习的设计模式,首先我们看下各个模式之间的关系图,下面这张图是网上比较典型的一个类图关 ...

最新文章

  1. mysql双主使用reset master清除日志要小心
  2. 最大输入hdu 2534 规律水题 求任意个a,b的和 不能表示的最大的数
  3. [快速数论变换 NTT]
  4. 敏捷个人2012.7月份线下活动报道:珠海 时中法、深圳 敏捷个人理念
  5. RabbitMQ(六)整合SpringBoot
  6. 计算机二级考点的选择题,2016年计算机二级考试试题选择题
  7. java 垃圾回收 新生代_Java垃圾回收
  8. 大数据可视化的优点有哪些
  9. 华为v3鸿蒙系统_重磅!华为鸿蒙系统问世!
  10. python代理ip连接失败_遇到问题--python--爬虫--使用代理ip第二次获取代理ip失败
  11. 云计算成就代码之美——首届阿里云开发者大赛巡礼
  12. 区块链ICO是什么意思?回答所有你关于ICO的问题
  13. html自动调音量,HTML5 音量调节控件
  14. 虚拟机安装和优盘启动盘制作
  15. 计算机科学与生命科学的关系,计算机科学与生命科学论文
  16. 折线分割平面问题总结
  17. 2023东莞理工学院计算机考研信息汇总
  18. 火狐浏览器firefox检测不到U盾证书
  19. JavaScript事件——【小案例】小人快跑
  20. MATLAB人工神经网络的手写数字识别系统

热门文章

  1. 深夜碎碎念,肿瘤NGS基因检测的寒冬
  2. 取消改写模式(python)
  3. [spring源码学习]六、IOC源码-BeanFactory和factory-bean
  4. 【FPGA——工具篇】:Modelsim SE-64 10.4下载、破解、安装过程
  5. 医学应用计算机答案,医学计算机应用试题及答案大全02.doc
  6. unity开发xbox手柄 驱动坑
  7. python分段函数编写程序_python分段函数如何编写?
  8. oracle中的userenv,Oracle 中的userenv()
  9. IOS开发百度地图API入门到精通-用点生成路线,导航,气泡响应
  10. 海豹突击队体能训练手册——前言