6大设计原则之2--里氏替换原则

面向对象语言中,继承是必不可少的、很是优秀的语言机制,它有以下优势:
  • 代码共享,减小建立类的工做量,每一个子类都拥有父类的方法和属性;设计

  • 提升代码的重用性对象

  • 子类能够形似父类,但又异于父类。继承

  • 提升代码的可扩展性,实现父类的方法就能够“随心所欲”了。接口

  • 提升产品或项目的开放性。开发

天然界是充满哲学的,又有点必有缺点。继承的缺点以下:
  • 继承是侵入性的。只要继承,就必须拥有父类的全部属性和方法;产品

  • 下降代码的灵活性。子类必须拥有父类的属性和方法,让子类的自由世界里多了些约束it

  • 加强了耦合性。当父类的常量、变量和方法被修改时,须要考虑子类的修改,并且在缺少规范的环境下,这种修改可能带来很是糟糕的结果--大段代码须要重构。io

什么是里氏替换原则呢?它有两种定义:
  • 第一种定义,也是最正宗的定义:If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.(若是对每个类型为S的对象o1,都有类型为T的对 象o2,使得以T定义的全部程序P在全部的对象o1都代换成o2时,程序P的行为没有发生变 化,那么类型S是类型T的子类型。)class

  • 第二种定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.(全部引用基类的地方必须能透明地使用其子类的 对象。)变量

第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就能够出现,并且 替换为子类也不会产生任何错误或异常,使用者可能根本就不须要知道是父类仍是子类。但 是,反过来就不行了,有子类出现的地方,父类未必就能适应。

里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了4层含义。

  1. 子类必须彻底实现父类的方法:注意 在类中调用其余类时务必要使用父类或接口,若是不能使用父类或接口,则说明 类的设计已经违背了LSP原则。

  2. 子类能够有本身的个性

  3. 覆盖或实现父类的方法时输入参数能够被放大:(方法中的输入参数称为前置条件,这是什么意思呢?你们作过Web Service开发就应该知 道有一个“契约优先”的原则,也就是先定义出WSDL接口,制定好双方的开发协议,而后再 各自实现。里氏替换原则也要求制定一个契约,就是父类或接口,这种设计方法也叫作 Design by Contract(契约设计),与里氏替换原则有着殊途同归之妙。契约制定了,也就同 时制定了前置条件和后置条件,前置条件就是你--父类要让我--子类执行,就必须知足个人条件;后置条 件就是我执行完了须要反馈,标准是什么。)

  4. 覆写或实现父类的方法时输出结果能够被缩小:(这是什么意思呢,父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆 写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一 个类型,要么S是T的子类,为何呢?分两种状况,若是是覆写,父类和子类的同名方法的 输入参数是相同的,两个方法的范围值S小于等于T,这是覆写的要求,这才是重中之重,子 类覆写父类的方法,天经地义。若是是重载,则要求方法的输入参数类型或数量不相同,在 里氏替换原则要求下,就是子类的输入参数宽于或等于父类的输入参数,也就是说你写的这 个方法是不会被调用的,参考上面讲的前置条件。)

采用里氏替换原则的目的就是加强程序的健壮性,版本升级时也能够保持很是好的兼容 性。即便增长子类,原有的子类还能够继续运行。在实际项目中,每一个子类对应不一样的业务 含义,使用父类做为参数,传递不一样的子类完成不一样的业务逻辑,很是完美!

在项目中,采用里氏替换原则时,尽可能避免子类的“个性”,一旦子类有“个性”,这个子 类和父类之间的关系就很难调和了,把子类当作父类使用,子类的“个性”被抹杀——委屈了 点;把子类单独做为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离——缺少类替 换的标准。

相关文章
相关标签/搜索