里氏替换原则(Liskov Substitution Principle)

目录

 

1、面向对象(oo)中继承的思考和说明

2、里氏替换原则基本介绍

3、应用实例

3.1、需求

3.2、传统方式实现

3.2.1、类图

3.2.2、代码

3.2.3、传统方式分析

3.3、遵循里氏替换原则实现

3.3.1、设计思路

3.3.2、类图

3.3.3、代码

3.3.4、里氏替换原则总结


1、面向对象(oo)中继承的思考和说明

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

2、里氏替换原则基本介绍

  • 里氏替换原则(Liskov Substitution Principle)在1988年,由麻省理工学院的一位姓里的女士提出的。指的是任何基类可以出现的地方,子类一定可以出现
  • 核心内容:继承必须确保超类所拥有的性质在子类中仍然成立也就是说在继承时,子类中不要去重写父类中已实现的方法
  • 如果每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象
  • 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
  • 里氏替换原则告诉我们,继承实际上让两个类耦合性增加了,在适当的情况下,可以通过聚合,组合,依赖来解决问题。

3、应用实例

3.1、需求

  • 电脑类:完成求和(a+b)的功能
  • 笔记本电脑类:完成求和再求差(a+b-c)的功能
  • 笔记本电脑类中可以使用电脑类中的求和方法

3.2、传统方式实现

3.2.1、类图

3.2.2、代码

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        System.out.println("1+2="+computer.calculate(1,2));
        
        NotebookComputer notebookComputer = new NotebookComputer();
        System.out.println("1+2-3="+notebookComputer.notebookCalculate(1,2,3));
    }
}

/**
 * 电脑
 */
class Computer{
    public int calculate(int num1,int num2){
        //求和
        return num1 + num2;
    }
}

/**
 * 笔记本电脑
 */
class NotebookComputer extends Computer{
    public int notebookCalculate(int num1,int num2,int num3){
        //先求和  在求差
        return calculate(num1,num2) - num3;
    }
}

运行结果:

3.2.3、传统方式分析

上面的代码设计符合基本需求,但是:如果程序员在NotebookComputer(笔记本电脑类)中将父类Computer(电脑类)中的求和方法calculate无意间重写了(这是程序员无意识的,刚好写了一个与父类的caculate方法一样的方法),会发生什么呢?

看代码:其他的不变,只更改了NotebookComputer(笔记本电脑类)

/**
 * 笔记本电脑
 */
class NotebookComputer extends Computer{

    //程序员无意间重写了求和方法,使其实现的功能发生了改变
    @Override
    public int calculate(int num1, int num2) {
        //父类的calculate是作加法,这里是作减法
        return num1 - num2;
    }

    public int notebookCalculate(int num1, int num2, int num3){
        //先求和  在求差
        return calculate(num1,num2) - num3;
    }
}

运行结果:

可见,这种继承是有很大几率出现问题的。当然,会出现的问题不只是上面的一种。

里氏替换原则的出现,就是为了解决诸如此类的问题。

3.3、遵循里氏替换原则实现

3.3.1、设计思路

  • 给电脑(Computer)和笔记本电脑(NotebookComputer)找一个公共的父类:电子产品(Electronics);
  • 电子产品类(Electronics)中可以写电脑和笔记本共有的特性;
  • 电脑和笔记本电脑之间的关系不再是继承,而是依赖(笔记本电脑中会用到电脑)

3.3.2、类图

3.3.3、代码

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        System.out.println("1+2="+computer.calculate(1,2));

        NotebookComputer notebookComputer = new NotebookComputer();
        System.out.println("1+2-3="+notebookComputer.calculate(1,2,3));
    }
}

/**
 * 电子产品类
 */
class Electronics{
    //可以写电脑与笔记本电脑共有的特征
}

/**
 * 电脑类
 */
class Computer extends Electronics{
    /**
     * 加法
     */
    public int calculate(int num1 ,int num2){
        return num1 + num2;
    }
}

/**
 * 笔记本电脑类
 */
class NotebookComputer extends Electronics{
    //依赖Computer类
    private Computer computer = new Computer();

    /**
     * 先加法 后减法
     */
    public int calculate(int num1 ,int num2,int num3){
        return computer.calculate(num1,num2) - num3;
    }
}

运行结果:

3.3.4、里氏替换原则总结

遵循里氏替换原则设计类的继承体系,可以避免前面所说的诸多问题。

里氏替换原则,简单用一句话来说就是:继承不重写、重载,父类出现的地方子类一定能出现,尽可能变继承为依赖。

本篇为我个人的理解思考与总结,有误之处请指出,谢谢 ^_^。

发布了98 篇原创文章 · 获赞 26 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_42425970/article/details/97364384