里氏替换原则

在决定是否需要用继承的方法来解决一个问题的时候,里氏替换原则可能会给出一些指导。

三条描述:

关于里氏替换原则,有一个很有意思的表述:

描述一:你不能通过给一条狗增加4条假腿来创造一只章鱼(Mario Fusco).

但是单独看这条表述,还是很难理解里氏替换原则到底在讲什么,里面说的狗指什么,假腿指代什么,章鱼又是指代什么。

另一些大牛给出过一本正经的阐述:

描述二:如果S类型是T类型的一个子类型,并假设q(x)是T类型对象相当一个可证的属性,那么同样的,q(y)应该是S类型对象y的一个可证的属性(Barbara Liskov, Jeanette Wing).

似乎仍然不太容易理解。

还有更通俗的说法:

描述三:使用基类指针或基类引用的函数,必须在不知道派生类的情况下使用它(Robert C. Martin).

这就清楚多了,在使用多态属性的时候,应该有所体会。我们提倡在定义时,或者作为函数的前置条件(也就是方法的形参)时使用基类,而在应用时再决定调用哪种派生类。这也是开闭原则和依赖倒置原则的基础。也就是说,派生类必须完全可以替代其基类。如果不能,就违反了里氏替换原则。因此里氏替换原则是符合开闭原则和依赖倒置原则的基础。

回过头再看开头那句关于章鱼和狗的描述,就不难理解:你不能通过继承一个描述狗的类,通过增加腿的数量得到一个描述章鱼的类。因为章鱼和狗完全不是同一种事物,即使他们在某些方面似乎有些共性(比如他们都包含了大于或等于四条腿)。

在通过继承创建一个新类的时候,我们可以扩展属性,但是不能增加属性的约束。

另一个很好的描述里氏替换原则的例子是《C++代码整洁之道》中列举的关于矩形和正方形的例子。

在数学上,我们说正方形是矩形的一个特例,但是在用C++类对其进行抽象的时候,我们能不能通过继承描述矩形的类来得到一个描述正方形的类呢?

当然,在实现上可能很简单,但这样就违反了里氏替换原则。

换句话说,由矩形到正方形,我们并不是扩展了属性,而是对现有属性进行了约束,那就是必须要求长和宽必须相等。

如果非要通过继承,并且不能违反里氏替换原则的基础上实现这一场景,就应该将矩形和正方形放在并列的位置上,共同继承更高一层的抽象。就像章鱼和狗可以共同继承自更高的抽象,比如一个描述动物的类。

于是我们就可以说,矩形和正方形都是几何图形,狗和章鱼都是动物。

你可能感兴趣的:(里氏替换原则,c++)