里氏替换原则详解--七大面向对象设计原则(2)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fanyun_01/article/details/51898787

里氏替换原则来源:

        我们都知道面向对象有三大特性:封装、继承、多态。所以我们在实际开发过程中,子类在继承父类后,根据多态的特性,可能是图一时方便,经常任意重写父类的方法,那么这种方式会大大增加代码出问题的几率。比如下面场景:类C实现了某项功能F1。现在需要对功能F1作修改扩展,将功能F1扩展为F,其中F由原有的功能F1和新功能F2组成。新功能F由类C的子类C1来完成,则子类C1在完成功能F的同时,有可能会导致类C的原功能F1发生故障。这时就有人提出了里氏替换原则。里氏替换原则这项原则最早是在1988年,由麻省理工学院一位姓里的女士(Liskov)提出来的。

里氏替换原则定义:

        严格的定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。 

  通俗的定义:所有引用基类的地方必须能透明地使用其子类的对象。

        更通俗的定义:子类可以扩展父类的功能,但不能改变父类原有的功能。

也就是说,在面向对象设计中,如果用一个基类对象替换一个子类对象,程序不会发生错误,但是软件实体使用用一个子类对象,但是改实体不一定能使用该子类的基类对象,如果使用,程序有可能就会出问题。

 例如有两个类,一个类为CLassA,另一个是CLassB类,并且CLassB类是CLassA类的子类,那么一个方法如果可以接受一个CLassA类型的基类对象base的话,如:MethodA(base),那么它必然可以接受一个CLassA类型的子类对象sub,MethodA(sub)能够正常运行。反过来的代换不成立,如一个方法MethodB接受CLassA类型的子类对象sub为参数:MethodB(sub),那么一般而言不可以有MethodB(base),除非是重载方法。

例子:沪深A股板块数据请求的里氏替换简析:

                                                              

        在本实例中,可以考虑增加一个新的抽象类StockBlock,而将ShangA和ShenA类作为其子类,数据请求类Quote类针对抽象客户类StockBlock编程,根据里氏代换原则,能够接受基类对象的地方必然能够接受子类对象,因此将Quote中的Request()方法的参数类型改为Code,如果需要增加新类型的客户,只需将其作为String类的子类即可。重构后的结构如图2所示:

                                         

 里氏替换使用总结:

          里氏替换包括以下四层含义:

(1).子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

(2).子类中可以增加自己特有的方法。

(3).当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

(4).当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。


展开阅读全文

没有更多推荐了,返回首页