继续阅读《设计模式之禅》第二章——里氏替换原则
,英文 Liskov Substiution Principle,简称 LSP,查了下这个 Liskov,全名 Barbara Liskov,是位大佬。
含义是父类能出现的地方,子类就可以出现,不会引起任何错误或异常。当然子类出现的地方,不要求父类能出现。
直觉上子类是拓展了父类,父类能做的事确实子类都应该能做到,子类可能有自己独有的东西,父类无法实现。
-
定义时尽量用父类或接口,这样使用时可以传递各种不同实现的子类。
-
在使用父类定义的逻辑中,如果对于某个子类需要单独处理,那就不要让它成为子类。
如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。`
书中举的例子是士兵可以用各种枪支杀敌,但传过来一把玩具枪就歇菜了,逻辑里需要单独判断类是不是玩具枪,这种写法打破了原有的逻辑,一种特例判断,不好。索性玩具枪自己单独一个类,没有依赖关系。
-
使用特定子类的地方,不一定还能用父类,比如
人
需要一个房子
睡觉,房子有子类别墅
、大三居
、地下室
、隔断
,给人配房子
那可以配各种子类,都能用来睡觉,但如果配的就是隔断
,直接传房子
就不行了,像我这种只能住10平方隔断的人,你塞来一个房子,那租金是1000还是10000,谁也保证不了,所以我明确就要住隔断
就请只给我传递隔断,当然传递隔断
的子类就又符合 LSP 了,比如传个暗隔
、明隔
、实隔
等等。 -
子类输入参数范围可以扩展
比如父类的方法参数是 HashMap,子类同名方法参数是 Map,方法名相同,参数类型不同,属于重载。
这样父类调用传一个 HashMap 参数,父类方法被执行,根据 LSP 原则,父类可以被替换为子类,还是执行子类从父类继承来的方法,即执行那个参数是 HashMap 的方法。
这是希望的。如果父类参数是 Map,子类是 HashMap 相当于范围缩小,这样父类传参 HashMap,执行到参数是 Map 的方法,当父类被子类替换后,会执行到子类参数是 HashMap 的方法,而不是从父类继承的参数为 Map 的方法。
这是不希望的,因为进入了子类自己的方法,根据 LSP 有父类的地方就可以用子类,本来是父类的通用逻辑,但是这样走子类却走入了子类特有逻辑。比如
// 父类 public class Person { public void eat(Breakfast bf) { print("太好吃了") } } // 子类 public class Star extends Person { public void eat(Breakfast50 bf) { print("650的早餐都不够?50元,你喂狗的吗") } } // 我 Person programmer = new Person(); // 苏老师 Star star = new Star(); // 50元的豪华早餐 Breakfast50 bf50 = new Breakfast50(); // 输出“太好吃了”,领导很开心,工人们还是很容易满足的嘛 programmer.eat(bf50); // 输出“650的早餐都不够?50元,你喂狗的吗“,领导脸黑了,我正在弘扬节约精神呢,你这狗东西敢打我脸 star.eat(bf50);
上面的打脸原因在于子类缩小了参数范围,在可以使用父类的地方改用子类就执行了子类特有的内容,引起了不适。如果反过来
public class Person { public void eat(Breakfast50 bf) { print("一顿早餐就50,也太豪华了吧") } } // 子类 public class Star extends Person { public void eat(Breakfast bf) { print("你这早餐多少钱,没1000就赶紧给我滚开") } } Person programmer = new Person(); Star star = new Star(); Breakfast50 bf50 = new Breakfast50(); programmer.eat(bf50); // 输出"一顿早餐就50,也太豪华了吧" star(bf50); // 输出"一顿早餐就50,也太豪华了吧"
无论什么人,吃 50 元早餐都很满足,你看贫富分化也看不出来了,社会也和谐了,领导也开心了。
-
子类返回值范围可以被缩小
重写时返回值必须是父类返回值的子类。重载时按照上面一条规则,如果参数是父类定义的参数类型,不会执行到子类,子类返回值也无所谓。
书里说最佳实践是尽量减少子类个性,但子类不就是要拥有各自的个性吗?把 Star 当普通 Person 去 eat 普通的 Breakfast,确实委屈了 Star,但为了隐藏贫富差距的矛盾,就得这么用,除非 Star 别继承 Person。
网友评论