在软件设计、编码过程中有几个基本原则即SOLID原则,学习理解能够帮忙我们写出更健壮的代码。SOLID是五个基本原则的首字母。这五个原则如下:
此篇来学习一下里氏替换原则(Liskov Substitution responsibility)
那么什么是里氏替换原则(LSP)呢?
Barbara Liskov 和 Jeannette Wing 在1994年的原文中是这么定义的:
Subtype Requirement: Let be a property provable about objects of type T. Then
should be true for objects of type S where S is a subtype of T.
原谅我蹩脚的英文,我个人理解意思就是:对于类型T的属性x可以推导出f(x),如果S是T的子类型,并且对于类型S的属性y有f(y)成立。
再引申一点讲就是:如果对于每一个类型为T的对象m,都有类型为S的对象n,满足以T定义的所以程序将对象m替换成n的时候,程序的行为没有改变,即T是S的父类,且子类可以替换父类。看上去好像挺好理解的,好像子类继承自父类,那么为什么不能替换呢,又不会报ClassCastException。然而(but),看官请往下看…
我们照例拿代码来举个反例例子(下面是我从网上找到的比较经典的例子):
矩形(Rectangle):
/**
* 矩形有两个属性,长(length)和宽(breadth)
*/
public class Rectangle {
private int length;
private int breadth;
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getBreadth() {
return breadth;
}
public void setBreadth(int breadth) {
this.breadth = breadth;
}
public int getArea() {
return this.length * this.breadth;
}
}
正方形(Square):
/**
* 正方形,正方形本来只有边长,但是为了便于理解我们直接Override了父类的方法
*/
class Square extends Rectangle {
@Override
public void setBreadth(int breadth) {
super.setLength(breadth);
super.setBreadth(breadth);
}
@Override
public void setLength(int length) {
super.setLength(length);
super.setBreadth(length);
}
}
那么我们来做个小测试:
public class LspTest
{
private static Rectangle getNewRectangle()
{
// it can be an object returned by some factory ...
// 返回Square实例
return new Square();
}
public static void main (String args[])
{
Rectangle r = LspTest.getNewRectangle();
r.setBreadth(5);
r.setLength(10);
// user knows that r it's a rectangle.
// 用户知道r是一个Rectangle类的实例
// It assumes that he's able to set the width and length as for the base class
// r实例可以设置width和length
System.out.println((r.getClass().getName()));
System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
// 输出结果让人惊讶,本来觉得应该是Rectangle和50,但是却是Rectangle和100,
// 所以这种情况不满足里氏替换原则
}
}
运行一下,输出的结果竟然是Rectangle和100,而不是Rectangle和50。
So,大家在设计类的体系结构的时候,一定要注意哈。举一个OK的例子:
比如今年公司年会,对于抽奖环节,全员参与。Boss可以抽奖、开发汪可以、运维汪也可以,QA小妹也可以,那么就是满足里氏替换原则的。祝大家年会都能抽中大奖!
参考《涉及模式之禅》里面的一句话:在项目中,采用里氏替换原则的时候,应该尽量避免子类的“个性”,一旦子类有“个性“,这个子类和父类之间的关系就很难调和了。
最后,欢迎大家批评指正哈!
参考:
https://en.wikipedia.org/wiki/Liskov_substitution_principle
http://blog.csdn.net/u011288271/article/details/52497602
https://www.oodesign.com/liskov-s-substitution-principle.html