som*_*raj 58 oop liskov-substitution-principle
我是设计和学习设计原则的新手.
它说从矩形推导出方形是违反Liskov替代原则的典型例子.
如果是这样的话,那么正确的设计应该是什么?
Ant*_*hyy 76
答案取决于可变性.如果你的矩形和方形类是不可变的,那么Square它实际上是一个子类型,Rectangle从第二个派生出来是完全可以的.否则,Rectangle并且Square可以暴露IRectangle没有变异器,但是从另一个中派生出一个是错误的,因为这两个类型都不是另一个的子类型.
Mat*_*ton 60
我相信推理是这样的:
假设您有一个接受矩形并调整其宽度的方法:
public void SetWidth(Rectangle rect, int width)
{
rect.Width = width;
}
Run Code Online (Sandbox Code Playgroud)
考虑到矩形是什么,假设该测试将通过,这应该是完全合理的:
Rectangle rect = new Rectangle(50, 20); // width, height
SetWidth(rect, 100);
Assert.AreEqual(20, rect.Height);
Run Code Online (Sandbox Code Playgroud)
...因为更改矩形的宽度不会影响其高度.
但是,假设您从Rectangle派生了一个新的Square类.根据定义,正方形的高度和宽度始终相等.让我们再试一次这个测试:
Rectangle rect = new Square(20); // both width and height
SetWidth(rect, 100);
Assert.AreEqual(20, rect.Height);
Run Code Online (Sandbox Code Playgroud)
该测试将失败,因为将正方形的宽度设置为100也将改变其高度.
因此,通过从矩形导出Square来违反Liskov的替换原则.
"is-a"规则在"真实世界"中是有意义的(正方形绝对是一种矩形),但并不总是在软件设计的世界中.
编辑
要回答你的问题,正确的设计应该是Rectangle和Square都来自一个普通的"Polygon"或"Shape"类,它不会强制执行任何有关宽度或高度的规则.
我最近一直在努力解决这个问题,并认为我应该加入我的帽子:
public class Rectangle {
protected int height;
protected int width;
public Rectangle (int height, int width) {
this.height = height;
this.width = width;
}
public int computeArea () { return this.height * this.width; }
public int getHeight () { return this.height; }
public int getWidth () { return this.width; }
}
public class Square extends Rectangle {
public Square (int sideLength) {
super(sideLength, sideLength);
}
}
public class ResizableRectangle extends Rectangle {
public ResizableRectangle (int height, int width) {
super(height, width);
}
public void setHeight (int height) { this.height = height; }
public void setWidth (int width) { this.width = width; }
}
Run Code Online (Sandbox Code Playgroud)
请注意最后一堂课ResizableRectangle。通过将“可调整大小”移至子类中,我们可以在实际改进模型的同时重用代码。可以这样想:正方形不能在保持正方形的情况下自由调整大小,而非正方形的矩形可以。但并非所有矩形都可以调整大小,因为正方形就是矩形(并且不能在保留其“身份”的同时自由调整大小)。Rectangle(o_O) 因此,创建一个不可调整大小的基类是有意义的,因为这是某些矩形的额外属性。
我不同意从矩形中导出square必然会违反LSP.
在Matt的例子中,如果你的代码依赖于宽度和高度是独立的,那么它确实违反了LSP.
但是,如果你可以在代码中的任何地方用矩形替换一个正方形而不破坏任何假设,那么你就不会违反LSP.
所以,它真的归结为抽象矩形意味着你的解决方案.