里氏替换原则的定义
里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和层次》(Data Abstraction and Hierarchy)里提出来的,她提出:继承必须确保超类所拥有的性质在子类中仍然成立
里氏替换原则的作用
里氏替换原则是实现开闭原则的重要方式之一。
它克服了继承中重写父类造成的可复用性变差的缺点,因为它推崇,子类可以新增方法,但是不要去覆盖父类已经写好的方法
它是动作正确性的保证,即类的扩展不会给已有的系统引入新的错误。降低了代码出错的可能性。因为里式替换原则保证了子类不要去覆盖父类方法,因此,新增新的子类时。父类定义的东西不会改变。也就是说,进行功能扩展时,原有的代码不会出错
里式替换原则的实现方法
里式替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类已经实现的方法。
如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是用多态用的比较频繁时,程序出错的概率就会变大。因为子类重写毕竟覆盖了父类的功能,当需要使用父类的功能时,就容易导致出错。而且,里氏替换和多态并不冲突,我们尽量在抽象类或者接口来做多态,简单父类一般只是用来自下而上的封装公有域。
如果程序违背了里式替换原则,则继承类的对象在基类出现的地方会出现运行错误。因为子类重写了方法,那么原本为基类的地方就不一定能用子类来代替了。我们如何判断程序是否违背了里式替换呢。判断方法如下。判断子类是否能继承父类的方法,如果可以继承,则符合里氏替换原则。如果不能继承,则不符合。意思就是,在使用父类的地方把子类代进去,如果方法不会出错,则符合。
下面以“几维鸟不是鸟”为例来说明里氏替换原则。
【例2】里氏替换原则在“几维鸟不是鸟”实例中的应用。
分析:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”,明显不符合预期,其类图如图 1 所示。
图1 “几维鸟不是鸟”实例的类图
程序代码如下:
- package principle;
- public class LSPtest
- {
- public static void main(String[] args)
- {
- Bird bird1=new Swallow();
- Bird bird2=new BrownKiwi();
- bird1.setSpeed(120);
- bird2.setSpeed(120);
- System.out.println("如果飞行300公里:");
- try
- {
- System.out.println("燕子将飞行"+bird1.getFlyTime(300)+"小时.");
- System.out.println("几维鸟将飞行"+bird2.getFlyTime(300)+"小时。");
- }
- catch(Exception err)
- {
- System.out.println("发生错误了!");
- }
- }
- }
- //鸟类
- class Bird
- {
- double flySpeed;
- public void setSpeed(double speed)
- {
- flySpeed=speed;
- }
- public double getFlyTime(double distance)
- {
- return(distance/flySpeed);
- }
- }
- //燕子类
- class Swallow extends Bird{}
- //几维鸟类
- class BrownKiwi extends Bird
- {
- public void setSpeed(double speed)
- {
- flySpeed=0;
- }
- }
程序的运行结果如下:
如果飞行300公里: 燕子将飞行2.5小时. 几维鸟将飞行Infinity小时。
程序运行错误的原因是:几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。正确的做法是:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。其类图如图 2 所示。
图2 “几维鸟是动物”实例的类图