Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >23种设计模式之里氏替换原则

23种设计模式之里氏替换原则

作者头像
暴躁的程序猿
发布于 2022-03-23 09:06:23
发布于 2022-03-23 09:06:23
18700
代码可运行
举报
运行总次数:0
代码可运行

里氏替换原则

OO中的继承性的思考和说明

1.继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。

2.继承再给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。

3.问题提出:在编程中,如何正确的使用继承? 里氏替换原则

里氏替换原则:是在1988年,麻省理工的一位姓里的女士提出的

如果对每个类型为T1的对象o1,都有类型T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引基类的地方必须能透明的使用其子类的对象。

在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法

里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题。

里氏替换原则的案例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 里氏替换原则
 *
 * @create: 2021/9/26
 * @author: Tony Stark
 */
public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3="+a.func1(11,3));
        System.out.println("1-8="+a.func1(1,8));
        B b = new B();
        System.out.println("11-3="+b.func1(11,3));
        System.out.println("1-8="+b.func1(1,8));
        System.out.println("11+3+9="+b.func2(11,3));

    }
}

/**
 *
 */
class A {
    /**
     * 返回两个数的差
     *
     * @param num1
     * @param num2
     * @return
     */
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

/**
 * B类继承了A  增加了一个新的功能 完成两个数相加  然后和9求和
 */
class B extends A{
    @Override
    public int func1(int a, int b) {
        return a+b;
    }
    public int func2(int a,int b){
        return func1(a,b)+9;
    }
}

输出

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
11-3=8
1-8=-7
11-3=14
1-8=9
11+3+9=23

这里我们B类的本意是调用方法进行 11-3的运算 但是因为我们B类重写了A类的方法 导致我们的11-3的结果变为了14

我们发现原来正常运行的相减功能发生了错误。原因就是类B无意中重写了父类的方法造成了原有功能出现错误

通用的做法:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉采用依赖,聚合,组合等关系代替。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 里氏替换原则
 *
 * @create: 2021/9/26
 * @author: Tony Stark
 */
public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));
        B b = new B();
        //因为B类不再继承A类因此调用者不会再认为 func1是求减法
        System.out.println("11+3=" + b.func1(11, 3));
        System.out.println("1+8=" + b.func1(1, 8));
        System.out.println("11+3+9=" + b.func2(11, 3));

        //使用组合仍然可以使用A的相关方法
        
    }
}

/**
 * 创建一个更加基础的基类
 */
class Base {
    //把更加基础的方法和成员写到Base类中

}

/**
 *
 */
class A extends Base {
    /**
     * 返回两个数的差
     *
     * @param num1
     * @param num2
     * @return
     */
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

/**
 * B类继承了A  增加了一个新的功能 完成两个数相加  然后和9求和
 */
class B extends Base {
    /**
     *如果B需要使用A的方法需要用到组合关系
     */
    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) + 9;
    }
    /**
     * 仍然想使用A类的方法
     */
    public int func3(int a,int b){
        return this.a.func1(a,b);
    }
}

输出

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
11-3=8
1-8=-7
11+3=14
1+8=9
11+3+9=23

此时我们要还想使用A的方法怎么办

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
System.out.println("11-3="+b.func3(11,3));
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));
        B b = new B();
        //因为B类不再继承A类因此调用者不会再认为 func1是求减法
        System.out.println("11+3=" + b.func1(11, 3));
        System.out.println("1+8=" + b.func1(1, 8));
        System.out.println("11+3+9=" + b.func2(11, 3));

        //使用组合仍然可以使用A的相关方法
        System.out.println("11-3="+b.func3(11,3));
    }
}

输出

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
11-3=8
1-8=-7
11+3=14
1+8=9
11+3+9=23
11-3=8

组合的方式依然可以使用A的方法

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/09/27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java设计模式:(1)设计模式七大设计原则-里氏替换原则
1)继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它并不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏
桑鱼
2020/03/17
4330
设计模式七大原则
编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等多方面的挑战,设计模式是为了让程序(软件),具有如下特征:
星哥玩云
2022/09/14
2990
设计模式七大原则
设计模式六大原则(2):里氏替换原则
        肯定有不少人跟我刚看到这项原则的时候一样,对这个原则的名字充满疑惑。其实原因就是这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。 定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。 定义2:所有引用基类的地方必须能透明地使用其子类的对象。 问题由来:有一功能P1,由类A完成。
Angel_Kitty
2018/04/08
5500
【设计模式】学习笔记(一)——基本概念和设计原则
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
鸡先生
2022/10/29
3360
【设计模式】学习笔记(一)——基本概念和设计原则
设计模式-里氏替换原则
在上面的三块代码中,当调用SmartTest类的resize方法的时候,如果传入的是父类,那么将会可以的,如果传入的是子类,正方形,那么将会不可以的。
mySoul
2018/11/19
4920
图解Java设计模式之设计模式七大原则
编写软件过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序(软件)。具有更好 1)代码重用性(即:相同功能的代码,不用多次编写) 2)可读性(即:编程规范性,便于其他程序员的阅读和理解) 3)可扩展性(即:当需要增加新的功能时,非常的方便,称为可维护) 4)可靠性(即:当我们增加新的功能后,对原来的功能没有影响) 5)使程序呈现高内聚,低耦合的特性 6)设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要“ 7)Scott Mayers 在其巨著《Effective C++》就曾经说过 :C++老手和C++新手的区别就是前者手背上有很多伤疤
海仔
2020/02/18
4710
图解Java设计模式之设计模式七大原则
设计模式六大原则(二)----里式替换原则
设计模式原则 之 里氏替换原则(LSP) 有多少小伙伴是不知道里式替换原则的? 我们写了好多年的代码, 天天都在用继承, 子类. 可是, 却不知道里式替换原则? 赶紧来看看吧. 一. 什么是里式替
用户7798898
2021/06/01
10K0
设计模式六大原则(二)----里式替换原则
java设计模式3,里氏替换原则
在面向对象的程序设计中,里氏替换原则(Liskov Substitution principle)是对子类型的特别定义。它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次会议上名为“数据的抽象与层次”的演说中首先提出。 里氏替换原则的内容可以描述为: “派生类(子类)对象可以在程序中代替其基类(超类)对象。” 以上内容并非利斯科夫的原文,而是译自罗伯特·马丁(Robert Martin)对原文的解读。 芭芭拉·利斯科夫与周以真(Jeannette Wing)在1994年发表论文并提出以上的Liskov代换原则。
全栈程序员站长
2022/11/18
6840
设计模式原则:里氏替换原则
里氏替换原则表示如果对每一个类型为 S 的对象 o1 都有类型为 T 的对象 o2 ,使得以 T 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时 ,程序 P 的行为没有发生变化 ,那么类型 S 是类型 T 的子类型。也就是说,在程序中可以将子类对象替换父类对象,而程序逻辑不变。
运维开发王义杰
2023/08/10
2150
设计模式原则:里氏替换原则
面向对象的7种设计原则(5)-里氏代换原则
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
一觉睡到小时候
2020/08/04
1.2K0
设计模式——二:里氏替换原则
先看看里氏替换原则(Liskov Substitution Principle)的定义:
三分恶
2020/07/16
4710
设计模式——七大原则
设计模式——七大原则
Java架构师必看
2021/05/14
3040
设计原则之里氏替换原则(LSP)
里氏替换原则是在做继承设计时需要遵循的原则,不遵循了 LSP 的继承类会带来意想不到的问题。
Dylan Liu
2019/07/01
1.2K0
设计模式 ☞ 七大设计原则之里氏替换原则
  里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的 "面向对象技术的高峰会议(OOPSLA)"上发表的一篇文章《数据抽象和层次》里提出来的,她提出:继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)。里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对实现抽象化的具体步骤的规范。 根据上述理解,对里氏替换原则的定义可以总结如下:  ♞ 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法  ♞ 子类中可以增加自己特有的方法  ♞ 子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松  ♞ 子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
Demo_Null
2020/12/18
5710
设计模式 ☞ 七大设计原则之里氏替换原则
里氏替换原则(LSP)
里氏替换原则(英文名为Liskov substitution principle,简称LSP)是由Barbara Liskov在1988年提出的,在Robert C. Martin提出的SOLID软件设计原则中的第三个字母L。
河边一枝柳
2022/06/21
6630
里氏替换原则(LSP)
软件架构设计原则--里氏替换原则
  里氏替换原则(Liskov Substitution Principle,LSP)是指,如果对每一个类型为T1的对象t1,都替换为类型为T2的对象t2,使得以T1定义的所有程序P在所有的对象t1都替换成t2时,程序P的行为没有发生变化,那么T2就是T1的子类型。   这个定义看上去比较抽象,我们重新理解一下。可以理解为一个软件实体如果适用于一个父类,那么一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类的对象能替换父类的对象,而程序逻辑不变。   根据这个理解,隐身含义为:子类可以扩展父类的功能,但不能改变父类原有的功能。
向着百万年薪努力的小赵
2022/12/02
3410
软件架构设计原则--里氏替换原则
软件架构设计原则之里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是指如果对每一个类型为T1的对象o1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
Tom弹架构
2021/10/24
4540
软件工程设计原理里氏替换原则举例
里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计的基本原则之一,由Barbara Liskov提出。这个原则指出,如果类 S 是类 T 的子类型,则程序中使用 T 的对象的地方都可以不经修改地使用 S 的对象。换句话说,子类的对象应该能够替换掉它们的父类对象,而不影响程序的正确性。这个原则强调了继承关系中的行为兼容性,保证了基类和派生类之间的正确抽象和继承关系。
小马哥学JAVA
2024/03/27
1390
里氏替换原则(Liskov Substitution Principle, LSP)
第一种:If for each object O1 of type S there is an object O2 fo type T such that for all programs P defined in terms of T, the behavior of P is unchanged when O1 is substitueted for O2 then S is a subtype of T. (对于每一个S类型的对象O1, 都有一个T类型的对象O2,使以T定义的程序P在使用O2替换O1时,行为不发生变化,则S是T的子类)。
刘开心_1266679
2019/02/14
9790
可能是最好的设计模式入门教程——里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计(OOD)中比较重要、常见的一种,下面来总结里氏替换原则的知识点,包括:
JavaEdge
2020/05/27
1.5K0
可能是最好的设计模式入门教程——里氏替换原则
推荐阅读
相关推荐
Java设计模式:(1)设计模式七大设计原则-里氏替换原则
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验