面向对象的7种设计原则(5)-里氏代换原则

栏目: IT技术 · 发布时间: 5年前

内容简介:里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。子类必须实现父类的抽象方法

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

原则

第一点

子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。

class Foo {
    public void cal(int num1, int num2) {
        int value = num1 + num2;
        System.out.println("父类计算结果: " + value);
    }
}

class Son extends Foo {
    public void cal(int num1, int num2) {
        int value = num1 - num2;
        System.out.println("子类计算结果:" + value);
    }
}

class Cal{
    public static void main(String[] args) {
        Foo foo = new Foo();
        foo.cal(2,1);
        Son son = new Son();
        son.cal(2,1);
    }
}

在类的继承中,我们的父类定义好的方法,并不会强制要求其子类必须完全遵守该方法的实现规则。子类是可以修改它继承自父类的任意方法的。

在本例中,父类的本意是想要定义一个两数相加的方法,但是子类继承该方法后却修改为减法,并且也成功了。子类这样操作后,会对整个继承体系造成破坏。当你想把使用父类的地方替换为其子类时,会发现原来的正常的功能现在出现问题了。

第二点

当子类需要重载父类中的方法的时候,子类方法的形参(入参)要比父类方法输入的参数更宽松(范围更广)。

class Foo {
    public void method(List arrayList) {
        System.out.println("父类方法执行");
    }
}

class Son extends Foo {
    public void method(ArrayList list) {
        System.out.println("子类方法执行" );
    }
}

class Cal{
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        Foo foo = new Foo();
        Son son = new Son();
        System.out.println("使用父类对象调用的结果:");
        foo.method(list);
        System.out.println("将父类对象替换为子类对象调用结果");
        son.method(list);
    }
}

//输出
使用父类对象调用的结果:
父类方法执行
将父类对象替换为子类对象调用结果
子类方法执行

我们的本意是希望对象替换后还执行原来的方法的,可结果却发生变化了。

修改

class Foo {
    public void method(ArrayList arrayList) {
        System.out.println("父类方法执行");
    }
}

class Son extends Foo {
    //重载了父类的method,并且方法入参比父类的入仓范围更广
    public void method(List list) {
        System.out.println("子类方法执行" );
    }
}

第三点

重写或者实现父类方法的时候,方法的返回值可以被缩小,但是不能放大。

正例:

class Foo {
    public List getList() {
        return new ArrayList();
    }
}

class Son extends Foo {
    public ArrayList getList() {
        return new ArrayList();
    }
}

反例:

class Foo {
    public ArrayList getList() {
        return new ArrayList();
    }
}

class Son extends Foo {
    public List getList() {
        return new ArrayList();
    }
}

如果我们试图在子类中放大,重写或实现来自父类方法的返回值时,代码会报错,连基本的编译器都无法通过。

第四点

子类可以拥有自己独特的方法或属性

class Foo {
    public void cal(int num1, int num2) {
        int value = num1 + num2;
        System.out.println("父类计算结果: " + value);
    }
}

class Son extends Foo {
    public void cal(int num1, int num2) {
        int value = num1 - num2;
        System.out.println("子类计算结果:" + value);
    }
    public void cal2(int num1, int num2) {
        int value = num1 + num2 +num2;
        System.out.println("子类计算结果:" + value);
    }
}

总结

通过上面的描述相信大家都对里氏替换原则有了一个基本的概念,其实它就是告诉我们在继承中需要注意什么问题和遵守什么规则。

然而在实际开发中我们在很多时候还是会违背该原则的,虽然表面上没有什么特别大的问题,但是这样做会大大增加代码的出错率。我们编写代码时不光要考虑怎么实现该功能,程序的健壮性和后期的扩展以及移植都是需要考虑到的。只有这样做才可以使我们的程序更加优秀。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

理解专业程序员

理解专业程序员

(美)杰拉尔德·温伯格(GeraldM.Weinberg) / 刘天北 / 清华大学出版社 / 2006-7 / 25.00元

《理解专业程序员》通过行内专家的独特视角,介绍了如何成为优秀程序员,如何提高工作绩效等问题。全书由多篇讨论程序员职业的短文组成,内容精彩绝伦,是一部任何在这个变化急剧的领域工作的人都不可错过的重要作品。本书论述生动翔实——你肯定能从中认出你自己和你的公司的故事——因此不仅极富教益,而且读来也引人入胜。 各篇主题包括:对于专业程序员重要的若干问题,成为专业程序员的途径,在企业官僚体......一起来看看 《理解专业程序员》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码