2012-02-16 94 views
5

我正在阅读简单继承的示例,并且遇到了基本想法,即正方形是基本类型,矩形是从正方形派生的。C#中的差继承示例#

用于设置方形尺寸的示例使用了名为Size的属性。 矩形的示例然后继续使用WidthHeight

这没有任何意义,所以我编码。

问题似乎是在访问rectangle时,总会出现一个名为'Size'的混淆属性。

我有这个权利吗?或者当看到rectangle时,有没有办法隐藏其他班级看到Size

public class square 
{ 
    public int Size { get; set; } 
    public square(int size) 
    { 
     this.Size = size; 
    } 
} 

public class rectangle : square 
{ 
    public int Width { get { return base.Size; } set { base.Size = value; } } 

    public int Height { get; set; } 

    public rectangle(int width, int height) 
     : base(width) 
    { 
     Height = height; 
    } 
} 
+7

它应该是周围的其他方法:方应该从矩形派生。一个正方形也有一个宽度和一个高度,它们恰好等于正方形。当然,矩形可以具有不同的值。 – xxbbcc 2012-02-16 22:41:54

+1

不是你在研究中遇到的第一个不好的继承例子,或者你在这个问题上的职业生涯。恭喜发现它,谷歌代码有时会闻到...... – 2012-02-16 22:51:47

+0

@Tod第35项是“考虑虚拟功能的替代品”。我的答案并不包含一个虚拟函数(事实上,除非你从'Square'或'Rectangle'派生另一个类,否则你不能改变任何一种类型的对象),所以请注意评论如何让我的答案“死了错?“ – 2012-02-16 22:58:36

回答

13

你是100%正确的,这是向后继承。相反,你应该有一个Square类继承Rectangle类,因为方形是一种特殊的矩形。

然后,你喜欢的东西

public class Rectangle 
{ 
    public int Width { get; private set; } 
    public int Height { get; private set; } 

    public Rectangle(int width, int height) 
    { 
     if (width <= 0 || height <= 0) 
      throw new ArgumentOutOfRangeException(); 
     Width = width; 
     Height = height; 
    } 
} 

public class Square : Rectangle 
{ 
    public int Size 
    { 
     get 
     { 
      return Width; 
     } 
    } 

    public Square(int size) 
     : base(size, size) 
    { 
    } 
} 
+5

拥有Square子类Rectangle并不一定是个好主意 - 虽然所有Squares都是Rectangles,但通过这种方式设计您的继承层次结构是违反Liskov Substitution原则的快速方法...... – 2012-02-16 22:44:32

+3

@ReedCopsey拥有'Square'子类'Rectangle',如果你最小化可变性,就像我在发布的代码中那样。 – 2012-02-16 22:45:49

+1

正确 - 我在编辑之前编写了该文件。然而,如果你允许类型的变异(例如OP的例子类),那么它是危险的。 – 2012-02-16 22:46:51

8

的问题是,一个矩形方 - 您也可以连说一个SquareRectangle因为这会导致很多问题太多,因为一个Rectangle(通常)提供的方法来单独设置宽度和高度 - 这将是Square约束 - 这是一个典型的违反Liskov substition principle. - 从维基百科报价:

违反LSP的典型示例是Square类,它从Rectangle类派生 ,假定存在 宽度和高度的getter和setter方法。 Square类始终假定宽度 与高度相等。如果在上下文 中使用Square对象(其中预计有Rectangle),则可能会发生意外的行为,因为 Square的尺寸不能(或者不应该)独立修改 。这个问题不容易修正:如果我们可以修改Square类中的setter方法,以便它们保留方形不变量(即保持尺寸相等),那么这些方法 将削弱(违反)Rectangle的后置条件设置器, 其中规定可以独立修改尺寸。 LSP的违例 与此类似,在实践中可能会也可能不会成为问题,取决于使用违反LSP的类的代码所期望的后置条件或不变量,实际上是 。在这里,可变性是一个关键问题 。如果Square和Rectangle只有getter方法(即 它们是不可变对象),则不会发生违反LSP的情况。

2

我认为这个问题是一个几何一个:-)

的矩形不是正方形。 正方形是一个矩形。

你应该颠倒继承,你会发现矩形只有宽度和高度,square有一个叫做Size的额外属性。

再见, 马科

3

遇到的基本想法,一个正方形是一个基本类型和矩形从正方形的。

的问题是,这是假 -

正方形是一个特定类型的矩形的,但是矩形不是正方形。

也就是说,制作方块继承矩形也是危险的,因为你最终会遇到意想不到的情况。这是一个common violation of the Liskov Substitution Principle,这就是为什么它往往是最好有两个SquareRectangle实现一个共同的基类,如Shape,这将只包含由两个类共享属性,如之类的东西AreaBounds

0

正方形总是矩形,但矩形并不总是正方形 - 因此Rectangle应该Square的父级,而不是相反。

0

几何101:正方形是矩形,但矩形不是正方形。

0

正方形和矩形是违反Liskov substitution principle的典型示例。例如,在这个原则中,两者都不是直接相关的,而可能与形状有关。

例如:

public class Rectangle 
{ 
    public int width {get;set;} 
    public int height {get;set;} 
    public int Area() { return width * height; } 
} 

public class Square : Rectangle 
{ 
    public override int width 
    { 
     get { return base.width; } 
     set { base.height = value; base.width = value; } 
    } 

    //... etc ... 
} 

[Test] 
public void Rectangles_area_should_equal_length_times_width() 
{ 
    Rectangle r = new Square(); 
    r.height = 10; 
    r.width = 15; 

    Assert.That(r.Area() == 150); // Fails 
} 

你看这个问题?从基类引用方块时,行为会以意想不到的方式发生变化。正确的解决方案是Square和Rectangle是兄弟姐妹(Shape的子女),而不是父母/孩子。

0

参考您的问题有关隐藏继承的成员,您可以使用new修改:

public class Rectangle : Square { 
    private new int Size { get; set; } 
    ... 
}