里氏代换原则由2008年图灵奖得主、美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出。传统的官方定义比较拗口且难以理解,这里,给出一个较为通俗易懂的定义:
所有引用基类(父类)的地方必须能透明地使用其子类的对象。
只要父类能出现的地方子类就可以出现,而且替换为子类还不产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。
下面通过具体程序实例进行进一步的解释。
父类作函数声明,但并不实现具体函数,以虚函数的形式呈现,即什么也不做,空实现。
子类一继承自父类SourceView,并具体实现 show 方法
子类二同样继承自父类SourceView,并具体实现 show 方法
最后在ViewController中引入,并实例化,最终运行结果如下:
由此,便用一个非常简单的实例演示了里氏代换原则。
里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
在使用里氏代换原则时需要注意如下几个问题:
子类必须实现父类所有非私有的属性和方法 或 子类的所有非私有属性和方法必须在父类中声明。即,子类可以有自己的“个性”,这也就是说,里氏代换原则可以正着用,不能反着用(在项目中,采用里氏替换原则时,尽量避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就很难调和了)。根据里氏代换原则,为了保证系统的扩展性,在程序中通常使用父类来进行定义,如果一个方法只存在子类中,在父类中不提供相应的声明,则无法在以父类定义的对象中使用该方法。
尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。