以下示例工作正常,但它有一个缺陷:Square
对象具有Width
的{{1}}和Height
属性。 Rectangle
对象的良好实现不会向用户提供这些属性:
Square
我想到了一些解决方法(包括新属性和public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public double Side
{
get { return Width; }
set { Width = Height = value; }
}
}
标记)。最好的解决方案是取消继承,而是将Obsolete
保留为Rectangle
对象的私有变量。这可行,但需要重新编写Square
的{{1}}方法,这违背了OOP的全部目的。请帮助我了解实现此目的的正确方法。
由于
答案 0 :(得分:2)
这是一个常见的问题,有些人回答" OOP不是银弹"。但是如果你真的想在这里使用OOP机制,你可以覆盖宽度,使其始终为正方形的高度。因此,如果您设置一个,另一个也会更改。不完美,但它有效。
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public override double Width { get { return Height; } set { Height = value; } }
}
答案 1 :(得分:2)
我不同意Square
不应提供Width
和Height
属性,因为正方形绝对具有宽度和高度,就像任何矩形一样。唯一的区别是它们必然是相同的。
我修复它的方法是使Rectangle
不可变,或允许Square
覆盖属性:
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
}
public class Square : Rectangle
{
public override int Width
{
get { return Side; }
set { Side = value; }
}
public override int Height
{
get { return Side; }
set { Side = value; }
}
public int Side { get; set; }
public Square(int side)
: base(side, side)
{
Side = side;
}
}
答案 2 :(得分:2)
不要从Square
继承Rectangle
。您试图将抽象之间的关系与它们所代表的对象之间的关系相同。但想想以下
当配偶离婚时,每个人都有代表他们的律师。这两位律师本身离婚的可能性很小。 因为事物的代表不分享他们所代表的事物的关系©Uncle Bob
您的Square
类代表方形几何形状。但它不是几何形状。这是一个代码。与Rectangle
类相同。这些代表不同意几何形状之间的关系。如果您尝试在代码中使用Square
和Rectangle
类来分享几何正方形和矩形之间的关系,那么让我们谈谈您将遇到的问题。
如果您从Square
继承Rectangle
,那么您可以将任何方格视为基类:
var rectangle = new Square { Side = 10 };
rectangle.Width = 20;
现在你有'正方形'物体,宽度为20,高度为10.你期望有这样的方块吗?好的,您可以同步这些属性。即当你改变宽度时,身高也会改变,反之亦然:
rectangle.Width = 5;
rectangle.Height = 10;
Assert.That(rectangle.Area, Is.EqualTo(50)); // wtf it fails?
如果使用基本类型(矩形)变量,您是否期望高度也是5?它不是矩形的有效行为。它违反了Liskov Substitution Principle。
如果您不从Square
继承Rectangle
,则不会出现任何问题。 Square将具有单个属性Side
,它将按预期运行。唯一可以从Square
继承Rectangle
而没有宽度或高度的意外值的情况 - 如果使这些对象不可变的话。但是另一个问题仍然存在 - 您的广场仍会有属性Width
和Height
这些令人困惑。它应该只有一个属性Side
。
答案 3 :(得分:1)
将Rectangle属性设置为virtual
将允许您覆盖其行为并使方形继承Rectangle。
有关详细信息,请参阅以下示例:
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public double Side { get; set; }
public override double Height
{
get { return Side; }
set { Side = value; }
}
public override double Width
{
get { return Side; }
set { Side = value; }
}
}