今天被我荒废了
仔细阅读本文大约需要2分57秒46毫秒
上篇文章(设计原则)
二、Liskov Substitution Principle(LSP)里氏替换原则
LSP的定义有两个:
第一种定义,也是最正宗的定义
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的子类型。)
第二种定义是
Functions that use pointers or references to base classes must be able to use objects of derved classes without knowing it.
(所有引用基类的地方必须能够透明地使用其子类的对象)
通过两个定义可以看出,LSP原则是围绕子类与超类进行的。
可能上面的两个定义并不能很清楚地让你明白什么是LSP。客官先不用着急,我们先看一下LSP的规范:
-
子类必须完全实现父类的方法
-
子类可以有自己的个性
-
覆盖或实现父类中的方法时输入的参数可以被放大
-
覆盖或实现父类的方法时输出的结果可以被缩小
看完规范可能更懵逼了,其实里氏替换理解起来很简单,就是能所有使用父类的地方都能够替换为子类,那说明子类要能够完成父类的功能,也就是子类的功能必须要大于等于类。而就父类被子类覆写或重构的方法来说,子类的这个方法如果需要能够完全替换父类,那么这个方法接受的参数范围必须要比父类的大。
例如:如果父类的方法要求传入String类型,子类就必须传入与父类范围相等String类型或者比父类范围大的Object类型。如果子类只能接收char类型的话,那么程序分分钟报错。
//父类方法
public void one(String str){
...
}
//子类覆写的方法
//与父类类型相同
public void one(String str){
...
}
//子类覆写的方法
//object类型的范围大于string
public void one(Object obj){
...
}
//子类覆写的方法
//char类型会报错
public void one(char c){
...
}
相对应的,子类覆写或重构的方法返回值必须小于等于父类。
画的有点丑,理解意思就行,不要哔哔。
客观看了那么多可能想这个李氏替换有个*用。
我们不妨来回忆一下,继承的优缺点。
优点:
-
代码共享
-
子类可以形似父类,但有异于父类。
-
提高代码的可扩展性。
-
提高产品或项目的开放性
缺点:
-
继承是入侵性的,只要继承,就必须拥有所有父类的属性和方法。
-
降低代码的灵活性,多了约束
-
增强了耦合性,当父类的变量需要修改时,需要考虑子类的修改,而在缺乏规范的前提下,这种修改可能是带来非常糟糕的结果,大量的代码需要重构!
里氏替换原则即使让继承的利发挥最大的作用,同时尽量减小弊带来的麻烦。
说白了里氏替换就是为了提高代码的质量而约束继承行为的原则。
看完了点个赞呗