前面的依赖倒转原则有用到里氏代换原则,那我就废话不多少说,直接来看看为什么用里氏代换原则代替继承吧。
里氏代换原则(LiskovSubstitutionPrinciple)
定义1:子类型必须能够替换掉它们的父类型。
定义2:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
描述:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化
例子:在生物学分类上,企鹅是一种鸟,但在编程世界里,企鹅却不能继承鸟。在面向对象设计时,子类拥有父类所有非private的行为和属性,鸟会飞,但企鹅不会飞,所以企鹅不能继承鸟类。
只有当子类可以替换掉父类,软件单位的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为,正是有里氏代换原则,使得继承复用成为了可能。正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展,不然还谈什么扩展开放,修改关闭呢
一个简单的例子:武打剧中大腕儿一般都有武术替身。为安全考虑以及表演效果,某些时候一般都是由武替(子类)代替武术大腕儿(父类)来完成。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。结合上面的例子,它包含以下4层含义:
1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。(武替可以代替大腕儿完成表演,但代替不了做明星)
2.当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。(表演效果只能比大腕儿演的好)
4.当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。(武替比大腕儿更擅长表演武术)