Oop 这是否解决了Liskov替换方形-矩形冲突?
我对坚实的设计原则非常陌生。我在理解上有一个问题,那就是Liskov替代原则违反的“方形-矩形”示例。为什么正方形的高度/宽度设置器要覆盖矩形的高度/宽度设置器?当存在多态性时,这不正是导致问题的原因吗 去掉这个难道不能解决问题吗Oop 这是否解决了Liskov替换方形-矩形冲突?,oop,solid-principles,liskov-substitution-principle,Oop,Solid Principles,Liskov Substitution Principle,我对坚实的设计原则非常陌生。我在理解上有一个问题,那就是Liskov替代原则违反的“方形-矩形”示例。为什么正方形的高度/宽度设置器要覆盖矩形的高度/宽度设置器?当存在多态性时,这不正是导致问题的原因吗 去掉这个难道不能解决问题吗 class Rectangle { public /*virtual*/ double Height { get; set; } public /*virtual*/ double Width { get; set; } public doub
class Rectangle
{
public /*virtual*/ double Height { get; set; }
public /*virtual*/ double Width { get; set; }
public double Area() { return Height * Width; }
}
class Square : Rectangle
{
double _width;
double _height;
public /*override*/ double Height
{
get
{
return _height;
}
set
{
_height = _width = value;
}
}
public /*override*/ double Width
{
get
{
return _width;
}
set
{
_width = _height = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Rectangle r = new Square();
r.Height = 5;
r.Width = 6;
Console.WriteLine(r.Area());
Console.ReadLine();
}
}
输出如预期的那样为30。假设用户正在GUI应用程序中实现一个边界框,如下所示: 他们想用一个
矩形
类来表示这个蓝色框,这样,如果用户单击并向下拖动,它的高度就会增加;如果用户向右拖动,其宽度将增加
LSP指出,客户机应该能够在使用其超类(矩形)的任何地方使用派生类(Square),而不会破坏矩形的业务逻辑,即,用户应该能够将一个派生类(Square)替换为另一个派生类&其代码的其余部分不应该中断
但以下几点互不兼容:
- 假设矩形的post条件是其setter方法不会引起副作用(即
不应影响高度)setWidth
- 正方形的逻辑是,它的宽度总是等于它的高度
方形/矩形示例的问题在于,我们对矩形的假设太多了。矩形的长度可以与其高度不同,但这是特定类型矩形(长方形矩形)的属性
正方形是一个矩形,但正方形不是一个长方形。如果我们想假设一个长方形关于我们的
矩形
类的行为(它的宽度和高度可以不同),那么我们的正方形
类从中扩展是没有意义的 LSP声明替换子类的对象不应改变程序的行为或正确性。您指定的类确实会更改正确性。对于矩形,类的客户端希望高度和宽度可以独立设置。当您使用Square子类时,情况就不再是这样了
客户端将宽度设置为5,高度设置为10,同时引用恰好是正方形但保存在矩形变量中的对象,将根据其设置高度和宽度属性的顺序获得不同的结果。他们可能会得到一个5x5或10x10的矩形。这两种情况都是出乎意料的
Barbara最初对LSP进行了复杂的描述,但Bob叔叔的描述使之更简单——“使用指向基类的指针或引用的函数必须能够在不知情的情况下使用派生类的对象”。方形/矩形问题打破了这一点
我在上写了一篇关于这方面的文章。这方面的问题是,
矩形的客户不希望设置一个维度会影响另一个维度。通常的解决方案是从一个称为形状或多边形等的共同祖先派生出正方形和矩形。我想说,具有可独立设置的宽度和高度不是一个简单的问题矩形的固有属性。即使矩形的宽度和高度不变,它仍然是矩形。因此,对于任何给定的矩形,不应假设其尺寸上存在任何约束(或缺少约束),这是合理的。我想说,一个保证宽度和高度可以独立调节的矩形,实际上不是一个纯矩形,它是一个矩形加上某些额外的保证行为。“替换子类的对象不应该改变行为”不是真的。Liskov principe说,如果程序模块使用基类,然后可以用派生类替换对基类的引用,而不会影响功能