2010-12-03 127 views
5

可能重复:
Is deriving square from rectangle a violation of Liskov's Substitution Principle?里氏的替换原则 - 如何建模正方形和长方形

通过应用LSP,任何人都可以给我正方形和长方形的实现?

我已经读过这本书 - “首先面向对象的分析和设计”,他们说如果Sqaure从Rectangle继承,它违反了LSP但没有正确的实现。

任何人都想试试吗?

+1

这是典型的LSP示例,问题一般是矩形有宽度和长度,但正方形只需要一个“边”:http://stackoverflow.com/questions/1030521/is-deriving-square-from- rectangle-a-violation-of-liskovs-substitution-principle – birryree 2010-12-03 18:25:15

+0

或者可能从`Quadrilateral`继承,而Quadrilateral继承自`Shape`。四边形都有四边,四个角度等。 – 2010-12-03 18:28:02

+0

@Loadmaster:四边形有同样的问题。如果我定义我的矩形来让我改变宽度和高度,那么大概我的四边形类让我重新定位四个顶点。如果我可以这样做,并且如果矩形和/或方形是四边形,那么顶点重新定位方法将违反LSP。根本的问题是,我们在小学几何学中学到的层次结构是基于形状是不变的假设。在数学中拉伸矩形不会改变矩形 - 它会产生一个新的矩形(通常称为“图像”)。 – 2010-12-03 18:37:49

回答

12

如果您使Square和Rectangle不可变,那么您将不会违反LSP。

问题是如果您可以独立更改矩形的宽度和高度,并且正方形是矩形,那么您可以将正方形更改为不是正方形。

1

我会说:不要

正方形是一个矩形的特殊情况。所以:使用矩形。它不清楚是否有充分的理由拥有一个独特的方形课程。

当然,这真的取决于你对这些形状做什么。 LSP是否满足取决于你在形状上的操作。

0

在构造函数中传递一个约束(bool square会这样做),将字段存储为字段并在计算'方形'期间检查字段(x,y,w,h?),从而加速这些计算的元素向上。

您可以这样做,如果设置了“方形”约束,则设置宽度或高度会导致另一个自动匹配。 set(x, y, w, h)方法将始终工作,但会抛出一个IllegalArgumentException或如果参数没有给一个正方形。

0

如果他们是不可改变的,上面比它不违反LSP作为中指出:

public class Rectangle { 
    int width; 
    int height; 

    public Rectangle(int w, int h) { 
     width = w; 
     height = h; 
    } 

    //getWidth(), getHeight, getArea(), etc, but no setters. 
} 


public Square extends Rectangle { 
    public Square(int side) { 
     super(side, side); 
    } 
} 

现在,如果你有一个scale()方法了,你可以成长的长方形和正方形在符合LSP路的百分比,但是矩形上的grow()方法会将两边被方块覆盖以正确行为,当然会违反LSP。

0

克林顿说得最好:要看是什么的的定义是

不可动摇的直觉,方矩形来自我们的数学训练。数学对象是不变的,无身份的。如果你的程序确实是在数学意义上建模正方形和矩形对象,那么Square应该是Rectangle的子类型,并且它们应该是不可变的。适用于矩形的任何数学运算适用于Square。

但是,您的程序可能不是建模数学对象。也许你正在建模图形屏幕对象。他们有数学方面,但是还有更多。然后我们陷入混乱。也许最好是将矩形设计为Square的子类型,考虑所有你想要放在它们上面的操作。那么它完全违背我们的数学直觉,我们不希望在我们的设计中出现这种混乱。

这是一个可怕的事实:OOP是meh。你可能认为一些超级聪明的人做了一些宏大的研究,并提出了这种全能的编程模型。对于每一个谜题都有一个完美的解决方案,你只是不知道它,因为你没有理解这个神圣的启示。人们争论OOP比宗教敌人更热心,把大字和抽象的概念相互抛在一边,引用古代文本中没有人真正理解的原则和惯例。