在C#中实现继承的正确方法

时间:2017-03-13 16:54:18

标签: c# oop inheritance

以下示例工作正常,但它有一个缺陷: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的全部目的。请帮助我了解实现此目的的正确方法。

由于

4 个答案:

答案 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不应提供WidthHeight属性,因为正方形绝对具有宽度和高度,就像任何矩形一样。唯一的区别是它们必然是相同的。

我修复它的方法是使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类相同。这些代表不同意几何形状之间的关系。如果您尝试在代码中使用SquareRectangle类来分享几何正方形和矩形之间的关系,那么让我们谈谈您将遇到的问题。

如果您从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而没有宽度或高度的意外值的情况 - 如果使这些对象不可变的话。但是另一个问题仍然存在 - 您的广场仍会有属性WidthHeight这些令人困惑。它应该只有一个属性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; }
    }
}