加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

设计模式六大原则(2):里氏替换原则

发布时间:2020-12-14 05:18:44 所属栏目:百科 来源:网络整理
导读:from?http://blog.csdn.net/zhengzhb/article/details/7281833 Liskov于1987年提出了一个关于继承的原则“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“ 继承必须确保超类所拥有的

from?http://blog.csdn.net/zhengzhb/article/details/7281833

Liskov于1987年提出了一个关于继承的原则“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“继承必须确保超类所拥有的性质在子类中仍然成立。”也就是说,当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系

理解为:

说明:子类型必须能够替换它们的基类型。一个软件实体如果使用的是一个基类,那么当把这个基类替换成继承该基类的子类,程序的行为不会发生任何变化。软件实体察觉不出基类对象和子类对象的区别。(也就是 说如果基类有一个对子类继承抽象方法,子类调用不会改变基类所要表达的意思,子类 和基类 调用同样的方法毫无区别)

优点:可以很容易的实现同一父类下各个子类的互换,而客户端可以毫不察觉。


继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。


举例说明继承的风险,我们需要完成一个两数相减的功能,由类A来负责。

[java]? view plain copy
  1. class?A{??
  2. ????public?int?func1(int?a,?int?b){??
  3. ????????return?a-b;??
  4. ????}??
  5. }??
  6. ??
  7. class?Client{??
  8. static?void?main(String[]?args){??
  9. ????????A?a?=?new?A();??
  10. ????????System.out.println("100-50="+a.func1(100,?50));??
  11. ????????System.out.println("100-80="+a.func1(80));??
  12. }??


?运行结果:

100-50=50
100-80=20

??????? 后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类B来负责。即类B需要完成两个功能:

  • 两数相减。
  • 两数相加,然后再加100。

??????? 由于类A已经实现了第一个功能,所以类B继承类A后,只需要再完成第二个功能就可以了,代码如下:

copy
    class?B?extends?A{??
  1. return?a+b;??
  2. ??????
  3. int?func2(return?func1(a,b)+100;??
  4. ????????B?b?=?new?B();??
  5. ????????System.out.println("100-50="+b.func1( ????????System.out.println("100-80="+b.func1( ????????System.out.println("100+20+100="+b.func2(20));??
  6. ????}??
  7. }??

类B完成后,运行结果:

100-50=150
100-80=180
100+20+100=220

??????? 我们发现原本运行正常的相减功能发生了错误。原因就是类B在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类B重写后的方法,造成原本运行正常的功能出现了错误。在本例中,引用基类A完成的功能,换成子类B之后,发生了异常。在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。

??????? 里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读