里氏替换原则
里氏替换原则描述的是子类应该能替换为它的基类。
意思是,给定 class B 是 class A 的子类,在预期传入 class A 的对象的任何方法传入 class B 的对象,方法都不应该有异常。
这是一个预期的行为,因为继承假定子类继承了父类的一切。子类可以扩展行为但不会收窄。
因此,当 class 违背这一原则时,会导致一些难于发现的讨厌的 bug。
里氏替换原则容易理解但是很难在代码里发现。看一个例子:
class Rectangle {
protected int width, height;
public Rectangle() {
}
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getArea() {
return width * height;
}
}
有一个简单的 Rectangle class,以及一个 getArea 方法返回矩形的面积。
现在准备创建另一个 Squares class。众所周知,正方形只不过是宽和高相等的特殊的矩形。
class Square extends Rectangle {
public Square() {}
public Square(int size) {
width = height = size;
}
@Override
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
@Override
public void setHeight(int height) {
super.setHeight(height);
super.setWidth(height);
}
}
我们的 Square class 继承自 Rectangle class。在构造器里设置宽和高相等,我们不希望任何客户端(在他们的代码里使用我们的 class)违背了正方形的特性将宽高改成不相等。
因此我们重载了 setter 使宽和高任何一个改变时都会同时改变宽高。这样一来,我们就违背了里氏替换原则。
让我们先编写一个 test 来测试 getArea 函数。
class Test {
static void getAreaTest(Rectangle r) {
int width = r.getWidth();
r.setHeight(10);
System.out.println("Expected area of " + (width * 10) + ", got " + r.getArea());
}
public static void main(String[] args) {
Rectangle rc = new Rectangle(2, 3);
getAreaTest(rc);
Rectangle sq = new Square();
sq.setWidth(5);
getAreaTest(sq);
}
}
团队的测试人员提出测试函数 getAreaTest ,然后告诉你正方形对象的 getArea 函数不能通过测试。
在第一个测试中,我们创建了一个宽为 2 高为 3 的矩形,然后调用 getAreaTest,预期输出为 20,但是当传入一个正方形时出错了。这是因为调用测试里的 setHeight 函数会同时设置 width,导致输出结果不符预期。
标签:原则,SOLID,public,height,width,int,面向对象编程,class,Rectangle From: https://www.cnblogs.com/gongxianjin/p/17590070.html