《设计模式》六大原则之一:里氏替换原则
《设计模式》六大原则:里氏替换原则1 什么是里氏代换原则里氏代换原则是由麻省理工学院(MIT)计算机科学实验室的Liskov女士,在1987年的OOPSLA大会上发表的一篇文章《Data Abstraction and Hierarchy》里面提出来的,主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中的蕴涵的原理。2002年,我们前面单一职责原则中提到的软件工程大师Robert C. Martin,出版了一本《Agile Software Development Principles Patterns and Practices》,在文中他把里氏代换原则最终简化为一句话:“Subtypes must be substitutable for their base types”。也就是,子类必须能够替换成它们的基类。 我们把里氏代换原则解释得更完整一些:在一个软件系统中,子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。 第一个实例:正方形不是长方形(违反里氏替换原则)“正方形不是长方形”是一个理解里氏代换原则的最经典的例子。在数学领域里,正方形毫无疑问是长方形,它是一个长宽相等的长方形。所以,我们开发的一个与几何图形相关的软件系统中,让正方形继承自长方形是顺利成章的事情。 现在,我们截取该系统的一个代码片段进行分析: 长方形类Rectangle: class Rectangle {
double length;
double width;
public double getLength() { return length; }
public void setLength(double height) { this.length = length; }
public double getWidth() { return width; }
public void setWidth(double width) { this.width = width; }
}
正方形类Square: class Square extends Rectangle {
public void setWidth(double width) {
super.setLength(width);
super.setWidth(width);
}
public void setLength(double length) {
super.setLength(length);
super.setWidth(length);
}
}
由于正方形的度和宽度必须相等,所以在方法setLength和setWidth中,对长度和宽度赋值相同。 类TestRectangle是我们的软件系统中的一个组件,它有一个resize方法要用到基类Rectangle,resize方法的功能是模拟长方形宽度逐步增长的效果: 测试类TestRectangle: class TestRectangle { public void resize(Rectangle objRect) { while(objRect.getWidth() <= objRect.getLength() ) { objRect.setWidth( objRect.getWidth () + 1 ); } } }
我们运行一下这段代码就会发现:
我们得出结论:在resize方法中,Rectangle类型的参数是不能被Square类型的参数所代替,如果进行了替换就得不到预期结果。因此,Square类和Rectangle类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立,正方形不是长方形。 总结里氏代换原则:在一个软件系统中,子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。 那么如何才能做到遵守里氏代换原则呢??? 里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能,如果改变了父类原有的功能,则将会导致派生类的行为功能和使用者对其基类的期望保持不一致带来错误。它包含以下4层含义:
关于继承这里还说几点
问题:如何正确地运用里氏代换原则里氏代换原则目的就是要保证继承关系的正确性。我们在实际的项目中,是不是对于每一个继承关系都得费这么大劲去斟酌?不需要,大多数情况下按照“Is-A”去设计继承关系是没有问题的,只有极少的情况下,需要你仔细处理一下。 参考资料:http://www.52php.cn/article/p-ceefgbij-xq.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |