注意:
a.在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则;
b.如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生”畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。
子类可以有自己的行为和外观,也就是方法与属性,那这里为什么要再提呢?
是因为里氏替换原则可以正着用,但是不能反着用。在子类出现的地方,父类未必能胜任。
方法中的输入参数称为前置条件,这是什么意思?
WebService有一个”契约优先”原则,也就是先定义出WSDL接口,制定好双方的开发协议,然后再各自实现。里氏替换原则也要求制定一个契约,就是父类或接口,这种设计方法也叫做契约设计,与里氏替换原则有着异曲同工之妙。契约制定了,也就同时制定了前置条件和后置条件,前置条件就是你要让我执行,就必须满足我的条件;后置条件就是我执行完了需要反馈,标准是什么。
这是什么意思呢?
父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一个类型,要么S是T的子类,为什么呢?
分两种情况:
如果是覆写,父类和子类的同名方法的输入参数是相同的,两个方法的范围值小于等于T,这是覆写的要求,这才是重中之重,子类覆写父类的方法,天经地义。
如果是重载,则要求方法的输入参数类型或数量不相同,在里氏替换原则要求下,就是子类的输入参数宽于或等于父类的输入参数,也就是说你写的这个方法是不会被调用的,参考上面讲的前置条件。
采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑。
3.小结在项目中,采用里氏替换原则时,尽量避免子类的”个性”,一旦子类有”个性”,这个子类和父类之间的关系就很难调和了,把子类当做父类使用,子类的”个性”被抹杀;把子类单独作为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离,缺乏类替换的标准。