[设计模式之禅读书笔记]002_设计模式六大原则(二):里氏替换原则(Liskov Substitution Principle)
序言
本节作者用了很大的篇幅来阐述自己对里氏替换原则的理解,而且代码片段也相当翔实。笔者阅读该节之后,认为该节的核心内容可以归结如下:
1. 里氏替换原则的定义
2. 里氏替换原则的规范
里氏替换原则的定义
里氏替换原则的定义有两种:
第一种(作者认为是最正宗的,但是却是理解起来稍微有点绕的)
如果对于每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2时,程序P的行为没有发生变化,那么类型S就是类型T的子类。
第二种(理解起来最方便的)
所有使用基类的地方必须能透明的使用其子类的对象。
里氏替换原则的规范
1. 子类必须完全实现父类的方法
2. 子类可以有自己的个性
3. 覆盖和实现父类的方法时,输入参数可以被放大,但不能被缩小
4. 覆盖和实现父类的方法时,输出结果可以被缩小,但不能被放大
1. 子类必须完全实现父类的方法
注意,这里说必须完全实现父类的方法,并不是说在子类里必须有父类的方法的实现体。而是要求在子类继承父类后,不能有未实现的方法。这一点其实编译器已经帮我们做好了。但是我们的角度不是技术角度,而是设计角度。
子类必须完全实现父类的方法在设计上有什么好处呢?里氏替换的核心:父类出现的地方,子类一定可以出现。这就要求父类中定义的方法,子类出现的时候,都必须有实现,否则会出错的。
2. 子类可以有自己的个性
当然,子类是可以有自己的个性的,这在自然界也是普遍存在的。而面向对象思想的显示根基就是现实的自然社会,所以这一点无可非议。
3. 覆盖和实现父类的方法时,输入参数可以被放大,但不能被缩小
理解这一点可能比较困难,书上的正反两个例子也还不错,但是作者的表达能力还是有限的,不能让人立马就明白。不过,也算不错的了,看两遍就能明白了。
这一点的意思是什么呢?一句话:
当覆盖或实现父类方法时,如果输入参数被缩小,那么传入的参数就必然执行子类的函数,这样父类的逻辑就会被覆盖,父类想保留的操作被覆盖,就引起业务上的混乱。
唉,我的表达能力也不咋地。
4. 覆盖和实现父类的方法时,输出结果可以被缩小,但不能被放大
这个跟3是类似的。这里不详述,无非是一些逻辑演变的过程。